Browse Source

[Profiling] Add status API (#96272)

With this commit we add a new REST API to the profiling plugin that
allows to retrieve its current status.

* Update docs/changelog/96272.yaml

* Enhance response structure
Daniel Mitterdorfer 2 years ago
parent
commit
08c0a9cd40

+ 5 - 0
docs/changelog/96272.yaml

@@ -0,0 +1,5 @@
+pr: 96272
+summary: "[Profiling] Add status API"
+area: Application
+type: enhancement
+issues: []

+ 107 - 0
x-pack/plugin/profiler/src/main/java/org/elasticsearch/xpack/profiler/GetStatusAction.java

@@ -0,0 +1,107 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.profiler;
+
+import org.elasticsearch.action.ActionRequestValidationException;
+import org.elasticsearch.action.ActionResponse;
+import org.elasticsearch.action.ActionType;
+import org.elasticsearch.action.support.master.AcknowledgedRequest;
+import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.io.stream.StreamInput;
+import org.elasticsearch.common.io.stream.StreamOutput;
+import org.elasticsearch.xcontent.ToXContentObject;
+import org.elasticsearch.xcontent.XContentBuilder;
+
+import java.io.IOException;
+import java.util.Objects;
+
+public class GetStatusAction extends ActionType<GetStatusAction.Response> {
+    public static final GetStatusAction INSTANCE = new GetStatusAction();
+    public static final String NAME = "cluster:monitor/profiling/status/get";
+
+    protected GetStatusAction() {
+        super(NAME, GetStatusAction.Response::new);
+    }
+
+    public static class Response extends ActionResponse implements ToXContentObject {
+
+        private boolean profilingEnabled;
+        private boolean resourceManagementEnabled;
+        private boolean resourcesCreated;
+
+        public Response(StreamInput in) throws IOException {
+            super(in);
+            profilingEnabled = in.readBoolean();
+            resourceManagementEnabled = in.readBoolean();
+            resourcesCreated = in.readBoolean();
+        }
+
+        public Response(boolean profilingEnabled, boolean resourceManagementEnabled, boolean resourcesCreated) {
+            this.profilingEnabled = profilingEnabled;
+            this.resourceManagementEnabled = resourceManagementEnabled;
+            this.resourcesCreated = resourcesCreated;
+        }
+
+        @Override
+        public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
+            builder.startObject();
+            builder.startObject("profiling").field("enabled", profilingEnabled).endObject();
+            builder.startObject("resource_management").field("enabled", resourceManagementEnabled).endObject();
+            builder.startObject("resources").field("created", resourcesCreated).endObject();
+            builder.endObject();
+            return builder;
+        }
+
+        @Override
+        public void writeTo(StreamOutput out) throws IOException {
+            out.writeBoolean(profilingEnabled);
+            out.writeBoolean(resourceManagementEnabled);
+            out.writeBoolean(resourcesCreated);
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) return true;
+            if (o == null || getClass() != o.getClass()) return false;
+            Response response = (Response) o;
+            return profilingEnabled == response.profilingEnabled
+                && resourceManagementEnabled == response.resourceManagementEnabled
+                && resourcesCreated == response.resourcesCreated;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(profilingEnabled, resourceManagementEnabled, resourcesCreated);
+        }
+
+        @Override
+        public String toString() {
+            return Strings.toString(this, true, true);
+        }
+
+    }
+
+    public static class Request extends AcknowledgedRequest<GetStatusAction.Request> {
+
+        public Request(StreamInput in) throws IOException {
+            super(in);
+        }
+
+        public Request() {}
+
+        @Override
+        public ActionRequestValidationException validate() {
+            return null;
+        }
+
+        @Override
+        public void writeTo(StreamOutput out) throws IOException {
+            super.writeTo(out);
+        }
+    }
+}

+ 9 - 6
x-pack/plugin/profiler/src/main/java/org/elasticsearch/xpack/profiler/ProfilingPlugin.java

@@ -40,13 +40,12 @@ import org.elasticsearch.watcher.ResourceWatcherService;
 import org.elasticsearch.xcontent.NamedXContentRegistry;
 import org.elasticsearch.xcontent.NamedXContentRegistry;
 import org.elasticsearch.xpack.core.XPackSettings;
 import org.elasticsearch.xpack.core.XPackSettings;
 
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.List;
 import java.util.List;
 import java.util.function.Supplier;
 import java.util.function.Supplier;
 
 
-import static java.util.Collections.singletonList;
-
 public class ProfilingPlugin extends Plugin implements ActionPlugin {
 public class ProfilingPlugin extends Plugin implements ActionPlugin {
     private static final Logger logger = LogManager.getLogger(ProfilingPlugin.class);
     private static final Logger logger = LogManager.getLogger(ProfilingPlugin.class);
     public static final Setting<Boolean> PROFILING_TEMPLATES_ENABLED = Setting.boolSetting(
     public static final Setting<Boolean> PROFILING_TEMPLATES_ENABLED = Setting.boolSetting(
@@ -117,11 +116,12 @@ public class ProfilingPlugin extends Plugin implements ActionPlugin {
         final IndexNameExpressionResolver indexNameExpressionResolver,
         final IndexNameExpressionResolver indexNameExpressionResolver,
         final Supplier<DiscoveryNodes> nodesInCluster
         final Supplier<DiscoveryNodes> nodesInCluster
     ) {
     ) {
+        List<RestHandler> handlers = new ArrayList<>();
+        handlers.add(new RestGetStatusAction());
         if (enabled) {
         if (enabled) {
-            return singletonList(new RestGetProfilingAction());
-        } else {
-            return Collections.emptyList();
+            handlers.add(new RestGetProfilingAction());
         }
         }
+        return Collections.unmodifiableList(handlers);
     }
     }
 
 
     @Override
     @Override
@@ -150,7 +150,10 @@ public class ProfilingPlugin extends Plugin implements ActionPlugin {
 
 
     @Override
     @Override
     public List<ActionHandler<? extends ActionRequest, ? extends ActionResponse>> getActions() {
     public List<ActionHandler<? extends ActionRequest, ? extends ActionResponse>> getActions() {
-        return List.of(new ActionHandler<>(GetProfilingAction.INSTANCE, TransportGetProfilingAction.class));
+        return List.of(
+            new ActionHandler<>(GetProfilingAction.INSTANCE, TransportGetProfilingAction.class),
+            new ActionHandler<>(GetStatusAction.INSTANCE, TransportGetStatusAction.class)
+        );
     }
     }
 
 
     @Override
     @Override

+ 38 - 0
x-pack/plugin/profiler/src/main/java/org/elasticsearch/xpack/profiler/RestGetStatusAction.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
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.profiler;
+
+import org.elasticsearch.client.internal.node.NodeClient;
+import org.elasticsearch.rest.BaseRestHandler;
+import org.elasticsearch.rest.RestRequest;
+import org.elasticsearch.rest.action.RestToXContentListener;
+
+import java.util.List;
+
+import static org.elasticsearch.rest.RestRequest.Method.GET;
+
+public class RestGetStatusAction extends BaseRestHandler {
+
+    @Override
+    public List<Route> routes() {
+        return List.of(new Route(GET, "/_profiling/status"));
+    }
+
+    @Override
+    public String getName() {
+        return "get_profiling_status_action";
+    }
+
+    @Override
+    protected RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) {
+        GetStatusAction.Request request = new GetStatusAction.Request();
+        request.timeout(restRequest.paramAsTime("timeout", request.timeout()));
+        request.masterNodeTimeout(restRequest.paramAsTime("master_timeout", request.masterNodeTimeout()));
+        return channel -> client.execute(GetStatusAction.INSTANCE, request, new RestToXContentListener<>(channel));
+    }
+}

+ 64 - 0
x-pack/plugin/profiler/src/main/java/org/elasticsearch/xpack/profiler/TransportGetStatusAction.java

@@ -0,0 +1,64 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+package org.elasticsearch.xpack.profiler;
+
+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.tasks.Task;
+import org.elasticsearch.threadpool.ThreadPool;
+import org.elasticsearch.transport.TransportService;
+import org.elasticsearch.xpack.core.XPackSettings;
+
+public class TransportGetStatusAction extends TransportMasterNodeAction<GetStatusAction.Request, GetStatusAction.Response> {
+
+    @Inject
+    public TransportGetStatusAction(
+        TransportService transportService,
+        ClusterService clusterService,
+        ThreadPool threadPool,
+        ActionFilters actionFilters,
+        IndexNameExpressionResolver indexNameExpressionResolver
+    ) {
+        super(
+            GetStatusAction.NAME,
+            transportService,
+            clusterService,
+            threadPool,
+            actionFilters,
+            GetStatusAction.Request::new,
+            indexNameExpressionResolver,
+            GetStatusAction.Response::new,
+            ThreadPool.Names.SAME
+        );
+    }
+
+    @Override
+    protected void masterOperation(
+        Task task,
+        GetStatusAction.Request request,
+        ClusterState state,
+        ActionListener<GetStatusAction.Response> listener
+    ) {
+        boolean pluginEnabled = XPackSettings.PROFILING_ENABLED.get(state.getMetadata().settings());
+        boolean resourceManagementEnabled = ProfilingPlugin.PROFILING_TEMPLATES_ENABLED.get(state.getMetadata().settings());
+        boolean resourcesCreated = ProfilingIndexTemplateRegistry.areAllTemplatesCreated(state);
+        listener.onResponse(new GetStatusAction.Response(pluginEnabled, resourceManagementEnabled, resourcesCreated));
+    }
+
+    @Override
+    protected ClusterBlockException checkBlock(GetStatusAction.Request request, ClusterState state) {
+        return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ);
+    }
+}