Browse Source

Add get autoscaling policy API (#54762)

This commit adds the get autoscaling policy API.
Jason Tedor 5 năm trước cách đây
mục cha
commit
48b314a806
14 tập tin đã thay đổi với 601 bổ sung1 xóa
  1. 2 0
      docs/reference/autoscaling/apis/autoscaling-apis.asciidoc
  2. 67 0
      docs/reference/autoscaling/apis/get-autoscaling-policy.asciidoc
  3. 5 1
      x-pack/plugin/autoscaling/qa/rest/src/test/resources/rest-api-spec/test/autoscaling/delete_autoscaling_policy.yml
  4. 34 0
      x-pack/plugin/autoscaling/qa/rest/src/test/resources/rest-api-spec/test/autoscaling/get_autoscaling_policy.yml
  5. 5 0
      x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/Autoscaling.java
  6. 120 0
      x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/action/GetAutoscalingPolicyAction.java
  7. 89 0
      x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/action/TransportGetAutoscalingPolicyAction.java
  8. 38 0
      x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/rest/RestGetAutoscalingPolicyHandler.java
  9. 25 0
      x-pack/plugin/autoscaling/src/test/java/org/elasticsearch/xpack/autoscaling/action/GetAutoscalingPolicyActionRequestWireSerializingTests.java
  10. 34 0
      x-pack/plugin/autoscaling/src/test/java/org/elasticsearch/xpack/autoscaling/action/GetAutoscalingPolicyActionResponseWireSerializingTests.java
  11. 8 0
      x-pack/plugin/autoscaling/src/test/java/org/elasticsearch/xpack/autoscaling/action/TransportDeleteAutoscalingPolicyActionIT.java
  12. 40 0
      x-pack/plugin/autoscaling/src/test/java/org/elasticsearch/xpack/autoscaling/action/TransportGetAutoscalingPolicyActionIT.java
  13. 110 0
      x-pack/plugin/autoscaling/src/test/java/org/elasticsearch/xpack/autoscaling/action/TransportGetAutoscalingPolicyActionTests.java
  14. 24 0
      x-pack/plugin/src/test/resources/rest-api-spec/api/autoscaling.get_autoscaling_policy.json

+ 2 - 0
docs/reference/autoscaling/apis/autoscaling-apis.asciidoc

@@ -11,9 +11,11 @@ You can use the following APIs to perform autoscaling operations.
 
 * <<autoscaling-get-autoscaling-decision,Get autoscaling decision>>
 * <<autoscaling-delete-autoscaling-policy,Delete autoscaling policy>>
+* <<autoscaling-get-autoscaling-policy,Get autoscaling policy>>
 * <<autoscaling-put-autoscaling-policy,Put autoscaling policy>>
 
 // top-level
 include::get-autoscaling-decision.asciidoc[]
 include::delete-autoscaling-policy.asciidoc[]
+include::get-autoscaling-policy.asciidoc[]
 include::put-autoscaling-policy.asciidoc[]

+ 67 - 0
docs/reference/autoscaling/apis/get-autoscaling-policy.asciidoc

@@ -0,0 +1,67 @@
+[role="xpack"]
+[testenv="platinum"]
+[[autoscaling-get-autoscaling-policy]]
+=== Get autoscaling policy API
+++++
+<titleabbrev>Get autoscaling policy</titleabbrev>
+++++
+
+Get autoscaling policy.
+
+[[autoscaling-get-autoscaling-policy-request]]
+==== {api-request-title}
+
+[source,console]
+--------------------------------------------------
+PUT /_autoscaling/policy/my_autoscaling_policy
+{
+  "policy": {
+    "deciders": {
+      "always": {
+      }
+    }
+  }
+}
+--------------------------------------------------
+// TESTSETUP
+
+[source,console]
+--------------------------------------------------
+GET /_autoscaling/policy/<name>
+--------------------------------------------------
+// TEST[s/<name>/my_autoscaling_policy/]
+
+[[autoscaling-get-autoscaling-policy-prereqs]]
+==== {api-prereq-title}
+
+* If the {es} {security-features} are enabled, you must have
+`manage_autoscaling` cluster privileges. For more information, see
+<<security-privileges>>.
+
+[[autoscaling-get-autoscaling-policy-desc]]
+==== {api-description-title}
+
+This API gets an autoscaling policy with the provided name.
+
+[[autoscaling-get-autoscaling-policy-examples]]
+==== {api-examples-title}
+
+This example gets an autoscaling policy named `my_autosaling_policy`.
+
+[source,console]
+--------------------------------------------------
+GET /_autoscaling/policy/my_autoscaling_policy
+--------------------------------------------------
+// TEST
+
+The API returns the following result:
+
+[source,console-result]
+--------------------------------------------------
+{
+  "policy": {
+     "deciders": <deciders>
+  }
+}
+--------------------------------------------------
+// TEST[s/<deciders>/$body.policy.deciders/]

+ 5 - 1
x-pack/plugin/autoscaling/qa/rest/src/test/resources/rest-api-spec/test/autoscaling/delete_autoscaling_policy.yml

@@ -14,7 +14,11 @@
       autoscaling.delete_autoscaling_policy:
         name: my_autoscaling_policy
 
-  # TODO: add validation that the policy is removed after we have a get policy API
+  # validate the policy does not exist
+  - do:
+      catch: /autoscaling policy with name \[my_autoscaling_policy\] does not exist/
+      autoscaling.get_autoscaling_policy:
+        name: my_autoscaling_policy
 
 ---
 "Test delete non-existent policy":

+ 34 - 0
x-pack/plugin/autoscaling/qa/rest/src/test/resources/rest-api-spec/test/autoscaling/get_autoscaling_policy.yml

@@ -0,0 +1,34 @@
+---
+"Test get autoscaling policy":
+  - do:
+      autoscaling.put_autoscaling_policy:
+        name: my_autoscaling_policy
+        body:
+          policy:
+            deciders:
+              always: {}
+
+  - match: { "acknowledged": true }
+
+  - do:
+      autoscaling.get_autoscaling_policy:
+        name: my_autoscaling_policy
+
+  - match: { policy.deciders.always: {} }
+
+  # test cleanup
+  - do:
+      autoscaling.delete_autoscaling_policy:
+        name: my_autoscaling_policy
+
+---
+"Test get non-existent autoscaling policy":
+  - do:
+      catch: bad_request
+      autoscaling.get_autoscaling_policy:
+        name: does_not_exist
+
+  - do:
+      catch: /autoscaling policy with name \[does_not_exist\] does not exist/
+      autoscaling.get_autoscaling_policy:
+        name: does_not_exist

+ 5 - 0
x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/Autoscaling.java

@@ -28,14 +28,17 @@ import org.elasticsearch.rest.RestController;
 import org.elasticsearch.rest.RestHandler;
 import org.elasticsearch.xpack.autoscaling.action.DeleteAutoscalingPolicyAction;
 import org.elasticsearch.xpack.autoscaling.action.GetAutoscalingDecisionAction;
+import org.elasticsearch.xpack.autoscaling.action.GetAutoscalingPolicyAction;
 import org.elasticsearch.xpack.autoscaling.action.PutAutoscalingPolicyAction;
 import org.elasticsearch.xpack.autoscaling.action.TransportDeleteAutoscalingPolicyAction;
 import org.elasticsearch.xpack.autoscaling.action.TransportGetAutoscalingDecisionAction;
+import org.elasticsearch.xpack.autoscaling.action.TransportGetAutoscalingPolicyAction;
 import org.elasticsearch.xpack.autoscaling.action.TransportPutAutoscalingPolicyAction;
 import org.elasticsearch.xpack.autoscaling.decision.AlwaysAutoscalingDecider;
 import org.elasticsearch.xpack.autoscaling.decision.AutoscalingDecider;
 import org.elasticsearch.xpack.autoscaling.rest.RestDeleteAutoscalingPolicyHandler;
 import org.elasticsearch.xpack.autoscaling.rest.RestGetAutoscalingDecisionHandler;
+import org.elasticsearch.xpack.autoscaling.rest.RestGetAutoscalingPolicyHandler;
 import org.elasticsearch.xpack.autoscaling.rest.RestPutAutoscalingPolicyHandler;
 import org.elasticsearch.xpack.core.XPackPlugin;
 
@@ -103,6 +106,7 @@ public class Autoscaling extends Plugin implements ActionPlugin {
             return List.of(
                 new ActionHandler<>(GetAutoscalingDecisionAction.INSTANCE, TransportGetAutoscalingDecisionAction.class),
                 new ActionHandler<>(DeleteAutoscalingPolicyAction.INSTANCE, TransportDeleteAutoscalingPolicyAction.class),
+                new ActionHandler<>(GetAutoscalingPolicyAction.INSTANCE, TransportGetAutoscalingPolicyAction.class),
                 new ActionHandler<>(PutAutoscalingPolicyAction.INSTANCE, TransportPutAutoscalingPolicyAction.class)
             );
         } else {
@@ -124,6 +128,7 @@ public class Autoscaling extends Plugin implements ActionPlugin {
             return List.of(
                 new RestGetAutoscalingDecisionHandler(),
                 new RestDeleteAutoscalingPolicyHandler(),
+                new RestGetAutoscalingPolicyHandler(),
                 new RestPutAutoscalingPolicyHandler()
             );
         } else {

+ 120 - 0
x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/action/GetAutoscalingPolicyAction.java

@@ -0,0 +1,120 @@
+/*
+ * 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.autoscaling.action;
+
+import org.elasticsearch.action.ActionRequestValidationException;
+import org.elasticsearch.action.ActionResponse;
+import org.elasticsearch.action.ActionType;
+import org.elasticsearch.action.support.master.MasterNodeReadRequest;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.common.xcontent.ToXContentObject;
+import org.elasticsearch.common.xcontent.XContentBuilder;
+import org.elasticsearch.xpack.autoscaling.policy.AutoscalingPolicy;
+
+import java.io.IOException;
+import java.util.Objects;
+
+public class GetAutoscalingPolicyAction extends ActionType<GetAutoscalingPolicyAction.Response> {
+
+    public static final GetAutoscalingPolicyAction INSTANCE = new GetAutoscalingPolicyAction();
+    public static final String NAME = "cluster:admin/autoscaling/get_autoscaling_policy";
+
+    private GetAutoscalingPolicyAction() {
+        super(NAME, Response::new);
+    }
+
+    public static class Request extends MasterNodeReadRequest<Request> {
+
+        private final String name;
+
+        public String name() {
+            return name;
+        }
+
+        public Request(final String name) {
+            this.name = Objects.requireNonNull(name);
+        }
+
+        public Request(final StreamInput in) throws IOException {
+            super(in);
+            name = in.readString();
+        }
+
+        @Override
+        public void writeTo(final StreamOutput out) throws IOException {
+            super.writeTo(out);
+            out.writeString(name);
+        }
+
+        @Override
+        public ActionRequestValidationException validate() {
+            return null;
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            final Request request = (Request) o;
+            return name.equals(request.name);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(name);
+        }
+
+    }
+
+    public static class Response extends ActionResponse implements ToXContentObject {
+
+        private final AutoscalingPolicy policy;
+
+        public AutoscalingPolicy policy() {
+            return policy;
+        }
+
+        public Response(final AutoscalingPolicy policy) {
+            this.policy = Objects.requireNonNull(policy);
+        }
+
+        public Response(final StreamInput in) throws IOException {
+            policy = new AutoscalingPolicy(in);
+        }
+
+        @Override
+        public void writeTo(final StreamOutput out) throws IOException {
+            policy.writeTo(out);
+        }
+
+        @Override
+        public XContentBuilder toXContent(final XContentBuilder builder, final Params params) throws IOException {
+            builder.startObject();
+            {
+                builder.field("policy", policy);
+            }
+            builder.endObject();
+            return builder;
+        }
+
+        @Override
+        public boolean equals(final Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            final Response response = (Response) o;
+            return policy.equals(response.policy);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(policy);
+        }
+
+    }
+
+}

+ 89 - 0
x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/action/TransportGetAutoscalingPolicyAction.java

@@ -0,0 +1,89 @@
+/*
+ * 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.autoscaling.action;
+
+import org.elasticsearch.action.ActionListener;
+import org.elasticsearch.action.support.ActionFilters;
+import org.elasticsearch.action.support.master.TransportMasterNodeAction;
+import org.elasticsearch.cluster.ClusterState;
+import org.elasticsearch.cluster.block.ClusterBlockException;
+import org.elasticsearch.cluster.block.ClusterBlockLevel;
+import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
+import org.elasticsearch.cluster.service.ClusterService;
+import org.elasticsearch.common.inject.Inject;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.tasks.Task;
+import org.elasticsearch.threadpool.ThreadPool;
+import org.elasticsearch.transport.TransportService;
+import org.elasticsearch.xpack.autoscaling.AutoscalingMetadata;
+import org.elasticsearch.xpack.autoscaling.policy.AutoscalingPolicy;
+
+import java.io.IOException;
+
+public class TransportGetAutoscalingPolicyAction extends TransportMasterNodeAction<
+    GetAutoscalingPolicyAction.Request,
+    GetAutoscalingPolicyAction.Response> {
+
+    @Inject
+    public TransportGetAutoscalingPolicyAction(
+        final TransportService transportService,
+        final ClusterService clusterService,
+        final ThreadPool threadPool,
+        final ActionFilters actionFilters,
+        final IndexNameExpressionResolver indexNameExpressionResolver
+    ) {
+        super(
+            GetAutoscalingPolicyAction.NAME,
+            transportService,
+            clusterService,
+            threadPool,
+            actionFilters,
+            GetAutoscalingPolicyAction.Request::new,
+            indexNameExpressionResolver
+        );
+    }
+
+    @Override
+    protected String executor() {
+        return ThreadPool.Names.SAME;
+    }
+
+    @Override
+    protected GetAutoscalingPolicyAction.Response read(final StreamInput in) throws IOException {
+        return new GetAutoscalingPolicyAction.Response(in);
+    }
+
+    @Override
+    protected void masterOperation(
+        final Task task,
+        final GetAutoscalingPolicyAction.Request request,
+        final ClusterState state,
+        final ActionListener<GetAutoscalingPolicyAction.Response> listener
+    ) {
+        listener.onResponse(new GetAutoscalingPolicyAction.Response(getAutoscalingPolicy(state, request.name())));
+    }
+
+    static AutoscalingPolicy getAutoscalingPolicy(final ClusterState state, final String name) {
+        final AutoscalingMetadata metadata;
+        if (state.metadata().custom(AutoscalingMetadata.NAME) != null) {
+            metadata = state.metadata().custom(AutoscalingMetadata.NAME);
+        } else {
+            // we will reject the request below when we try to look up the policy by name
+            metadata = AutoscalingMetadata.EMPTY;
+        }
+        if (metadata.policies().containsKey(name) == false) {
+            throw new IllegalArgumentException("autoscaling policy with name [" + name + "] does not exist");
+        }
+        return metadata.policies().get(name).policy();
+    }
+
+    @Override
+    protected ClusterBlockException checkBlock(final GetAutoscalingPolicyAction.Request request, final ClusterState state) {
+        return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ);
+    }
+
+}

+ 38 - 0
x-pack/plugin/autoscaling/src/main/java/org/elasticsearch/xpack/autoscaling/rest/RestGetAutoscalingPolicyHandler.java

@@ -0,0 +1,38 @@
+/*
+ * 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.autoscaling.rest;
+
+import org.elasticsearch.client.node.NodeClient;
+import org.elasticsearch.rest.BaseRestHandler;
+import org.elasticsearch.rest.RestRequest;
+import org.elasticsearch.rest.action.RestToXContentListener;
+import org.elasticsearch.xpack.autoscaling.action.GetAutoscalingPolicyAction;
+
+import java.util.List;
+
+import static org.elasticsearch.rest.RestRequest.Method.GET;
+
+public class RestGetAutoscalingPolicyHandler extends BaseRestHandler {
+
+    @Override
+    public List<Route> routes() {
+        return List.of(new Route(GET, "/_autoscaling/policy/{name}"));
+    }
+
+    @Override
+    public String getName() {
+        return "get_autoscaling_policy";
+    }
+
+    @Override
+    protected RestChannelConsumer prepareRequest(final RestRequest restRequest, final NodeClient client) {
+        final String name = restRequest.param("name");
+        final GetAutoscalingPolicyAction.Request request = new GetAutoscalingPolicyAction.Request(name);
+        return channel -> client.execute(GetAutoscalingPolicyAction.INSTANCE, request, new RestToXContentListener<>(channel));
+    }
+
+}

+ 25 - 0
x-pack/plugin/autoscaling/src/test/java/org/elasticsearch/xpack/autoscaling/action/GetAutoscalingPolicyActionRequestWireSerializingTests.java

@@ -0,0 +1,25 @@
+/*
+ * 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.autoscaling.action;
+
+import org.elasticsearch.common.io.stream.Writeable;
+import org.elasticsearch.test.AbstractWireSerializingTestCase;
+
+public class GetAutoscalingPolicyActionRequestWireSerializingTests extends AbstractWireSerializingTestCase<
+    GetAutoscalingPolicyAction.Request> {
+
+    @Override
+    protected Writeable.Reader<GetAutoscalingPolicyAction.Request> instanceReader() {
+        return GetAutoscalingPolicyAction.Request::new;
+    }
+
+    @Override
+    protected GetAutoscalingPolicyAction.Request createTestInstance() {
+        return new GetAutoscalingPolicyAction.Request(randomAlphaOfLength(8));
+    }
+
+}

+ 34 - 0
x-pack/plugin/autoscaling/src/test/java/org/elasticsearch/xpack/autoscaling/action/GetAutoscalingPolicyActionResponseWireSerializingTests.java

@@ -0,0 +1,34 @@
+/*
+ * 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.autoscaling.action;
+
+import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
+import org.elasticsearch.common.io.stream.Writeable;
+import org.elasticsearch.test.AbstractWireSerializingTestCase;
+import org.elasticsearch.xpack.autoscaling.AutoscalingTestCase;
+
+import static org.elasticsearch.xpack.autoscaling.AutoscalingTestCase.randomAutoscalingPolicy;
+
+public class GetAutoscalingPolicyActionResponseWireSerializingTests extends AbstractWireSerializingTestCase<
+    GetAutoscalingPolicyAction.Response> {
+
+    @Override
+    protected Writeable.Reader<GetAutoscalingPolicyAction.Response> instanceReader() {
+        return GetAutoscalingPolicyAction.Response::new;
+    }
+
+    @Override
+    protected GetAutoscalingPolicyAction.Response createTestInstance() {
+        return new GetAutoscalingPolicyAction.Response(randomAutoscalingPolicy());
+    }
+
+    @Override
+    protected NamedWriteableRegistry getNamedWriteableRegistry() {
+        return AutoscalingTestCase.getAutoscalingNamedWriteableRegistry();
+    }
+
+}

+ 8 - 0
x-pack/plugin/autoscaling/src/test/java/org/elasticsearch/xpack/autoscaling/action/TransportDeleteAutoscalingPolicyActionIT.java

@@ -14,6 +14,7 @@ import org.elasticsearch.xpack.autoscaling.policy.AutoscalingPolicy;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
 import static org.elasticsearch.xpack.autoscaling.AutoscalingTestCase.randomAutoscalingPolicy;
 import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.hasKey;
 import static org.hamcrest.Matchers.not;
 
@@ -31,6 +32,13 @@ public class TransportDeleteAutoscalingPolicyActionIT extends AutoscalingIntegTe
         final AutoscalingMetadata metadata = state.metadata().custom(AutoscalingMetadata.NAME);
         assertNotNull(metadata);
         assertThat(metadata.policies(), not(hasKey(policy.name())));
+        // and verify that we can not obtain the policy via get
+        final GetAutoscalingPolicyAction.Request getRequest = new GetAutoscalingPolicyAction.Request(policy.name());
+        final IllegalArgumentException e = expectThrows(
+            IllegalArgumentException.class,
+            () -> client().execute(GetAutoscalingPolicyAction.INSTANCE, getRequest).actionGet()
+        );
+        assertThat(e.getMessage(), equalTo("autoscaling policy with name [" + policy.name() + "] does not exist"));
     }
 
     public void testDeleteNonExistentPolicy() {

+ 40 - 0
x-pack/plugin/autoscaling/src/test/java/org/elasticsearch/xpack/autoscaling/action/TransportGetAutoscalingPolicyActionIT.java

@@ -0,0 +1,40 @@
+/*
+ * 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.autoscaling.action;
+
+import org.elasticsearch.xpack.autoscaling.AutoscalingIntegTestCase;
+import org.elasticsearch.xpack.autoscaling.policy.AutoscalingPolicy;
+
+import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
+import static org.elasticsearch.xpack.autoscaling.AutoscalingTestCase.randomAutoscalingPolicyOfName;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+
+public class TransportGetAutoscalingPolicyActionIT extends AutoscalingIntegTestCase {
+
+    public void testGetPolicy() {
+        final String name = randomAlphaOfLength(8);
+        final AutoscalingPolicy expectedPolicy = randomAutoscalingPolicyOfName(name);
+        final PutAutoscalingPolicyAction.Request putRequest = new PutAutoscalingPolicyAction.Request(expectedPolicy);
+        assertAcked(client().execute(PutAutoscalingPolicyAction.INSTANCE, putRequest).actionGet());
+        // we trust that the policy is in the cluster state since we have tests for putting policies
+        final GetAutoscalingPolicyAction.Request getRequest = new GetAutoscalingPolicyAction.Request(name);
+        final AutoscalingPolicy actualPolicy = client().execute(GetAutoscalingPolicyAction.INSTANCE, getRequest).actionGet().policy();
+        assertThat(expectedPolicy, equalTo(actualPolicy));
+    }
+
+    public void testGetNonExistentPolicy() {
+        final String name = randomAlphaOfLength(8);
+        final GetAutoscalingPolicyAction.Request getRequest = new GetAutoscalingPolicyAction.Request(name);
+        final IllegalArgumentException e = expectThrows(
+            IllegalArgumentException.class,
+            () -> client().execute(GetAutoscalingPolicyAction.INSTANCE, getRequest).actionGet()
+        );
+        assertThat(e.getMessage(), containsString("autoscaling policy with name [" + name + "] does not exist"));
+    }
+
+}

+ 110 - 0
x-pack/plugin/autoscaling/src/test/java/org/elasticsearch/xpack/autoscaling/action/TransportGetAutoscalingPolicyActionTests.java

@@ -0,0 +1,110 @@
+/*
+ * 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.autoscaling.action;
+
+import org.elasticsearch.action.support.ActionFilters;
+import org.elasticsearch.cluster.ClusterName;
+import org.elasticsearch.cluster.ClusterState;
+import org.elasticsearch.cluster.block.ClusterBlock;
+import org.elasticsearch.cluster.block.ClusterBlockException;
+import org.elasticsearch.cluster.block.ClusterBlockLevel;
+import org.elasticsearch.cluster.block.ClusterBlocks;
+import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
+import org.elasticsearch.cluster.metadata.Metadata;
+import org.elasticsearch.cluster.service.ClusterService;
+import org.elasticsearch.rest.RestStatus;
+import org.elasticsearch.threadpool.ThreadPool;
+import org.elasticsearch.transport.TransportService;
+import org.elasticsearch.xpack.autoscaling.AutoscalingMetadata;
+import org.elasticsearch.xpack.autoscaling.AutoscalingTestCase;
+import org.elasticsearch.xpack.autoscaling.policy.AutoscalingPolicy;
+
+import java.util.EnumSet;
+
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+import static org.mockito.Mockito.mock;
+
+public class TransportGetAutoscalingPolicyActionTests extends AutoscalingTestCase {
+
+    public void testReadBlock() {
+        final TransportGetAutoscalingPolicyAction action = new TransportGetAutoscalingPolicyAction(
+            mock(TransportService.class),
+            mock(ClusterService.class),
+            mock(ThreadPool.class),
+            mock(ActionFilters.class),
+            mock(IndexNameExpressionResolver.class)
+        );
+        final ClusterBlocks blocks = ClusterBlocks.builder()
+            .addGlobalBlock(
+                new ClusterBlock(
+                    randomIntBetween(128, 256),
+                    "metadata read block",
+                    false,
+                    false,
+                    false,
+                    RestStatus.SERVICE_UNAVAILABLE,
+                    EnumSet.of(ClusterBlockLevel.METADATA_READ)
+                )
+            )
+            .build();
+        final ClusterState state = ClusterState.builder(new ClusterName(randomAlphaOfLength(8))).blocks(blocks).build();
+        final ClusterBlockException e = action.checkBlock(new GetAutoscalingPolicyAction.Request(randomAlphaOfLength(8)), state);
+        assertThat(e, not(nullValue()));
+    }
+
+    public void testNoReadBlock() {
+        final TransportGetAutoscalingPolicyAction action = new TransportGetAutoscalingPolicyAction(
+            mock(TransportService.class),
+            mock(ClusterService.class),
+            mock(ThreadPool.class),
+            mock(ActionFilters.class),
+            mock(IndexNameExpressionResolver.class)
+        );
+        final ClusterBlocks blocks = ClusterBlocks.builder().build();
+        final ClusterState state = ClusterState.builder(new ClusterName(randomAlphaOfLength(8))).blocks(blocks).build();
+        final ClusterBlockException e = action.checkBlock(new GetAutoscalingPolicyAction.Request(randomAlphaOfLength(8)), state);
+        assertThat(e, nullValue());
+    }
+
+    public void testGetPolicy() {
+        final ClusterState state;
+        {
+            final ClusterState.Builder builder = ClusterState.builder(new ClusterName(randomAlphaOfLength(8)));
+            builder.metadata(
+                Metadata.builder().putCustom(AutoscalingMetadata.NAME, randomAutoscalingMetadataOfPolicyCount(randomIntBetween(1, 8)))
+            );
+            state = builder.build();
+        }
+        final AutoscalingMetadata metadata = state.metadata().custom(AutoscalingMetadata.NAME);
+        final String name = randomFrom(metadata.policies().keySet());
+        final AutoscalingPolicy policy = TransportGetAutoscalingPolicyAction.getAutoscalingPolicy(state, name);
+
+        assertThat(metadata.policies().get(name).policy(), equalTo(policy));
+    }
+
+    public void testGetNonExistentPolicy() {
+        final ClusterState state;
+        {
+            final ClusterState.Builder builder = ClusterState.builder(new ClusterName(randomAlphaOfLength(8)));
+            builder.metadata(
+                Metadata.builder().putCustom(AutoscalingMetadata.NAME, randomAutoscalingMetadataOfPolicyCount(randomIntBetween(1, 8)))
+            );
+            state = builder.build();
+        }
+        final AutoscalingMetadata metadata = state.metadata().custom(AutoscalingMetadata.NAME);
+        final String name = randomValueOtherThanMany(metadata.policies().keySet()::contains, () -> randomAlphaOfLength(8));
+        final IllegalArgumentException e = expectThrows(
+            IllegalArgumentException.class,
+            () -> TransportGetAutoscalingPolicyAction.getAutoscalingPolicy(state, name)
+        );
+        assertThat(e.getMessage(), containsString("autoscaling policy with name [" + name + "] does not exist"));
+    }
+
+}

+ 24 - 0
x-pack/plugin/src/test/resources/rest-api-spec/api/autoscaling.get_autoscaling_policy.json

@@ -0,0 +1,24 @@
+{
+  "autoscaling.get_autoscaling_policy":{
+    "documentation":{
+      "url":"https://www.elastic.co/guide/en/elasticsearch/reference/current/autoscaling-get-autoscaling-policy.html"
+    },
+    "stability":"experimental",
+    "url":{
+      "paths":[
+        {
+          "path":"/_autoscaling/policy/{name}",
+          "methods":[
+            "GET"
+          ],
+          "parts":{
+            "name":{
+              "type":"string",
+              "description":"the name of the autoscaling policy"
+            }
+          }
+        }
+      ]
+    }
+  }
+}