mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-20 03:45:02 +00:00
Merge remote-tracking branch 'elastic/master' into feature/sql_2
Original commit: elastic/x-pack-elasticsearch@79e7b1b953
This commit is contained in:
commit
292506526e
@ -1 +1,2 @@
|
|||||||
org.gradle.daemon=false
|
org.gradle.daemon=false
|
||||||
|
org.gradle.jvmargs=-Xmx1536m
|
||||||
|
@ -47,6 +47,7 @@ dependencyLicenses {
|
|||||||
ignoreSha 'shared-proto'
|
ignoreSha 'shared-proto'
|
||||||
ignoreSha 'elasticsearch-rest-client-sniffer'
|
ignoreSha 'elasticsearch-rest-client-sniffer'
|
||||||
ignoreSha 'aggs-matrix-stats'
|
ignoreSha 'aggs-matrix-stats'
|
||||||
|
ignoreSha 'x-pack-core'
|
||||||
}
|
}
|
||||||
|
|
||||||
licenseHeaders {
|
licenseHeaders {
|
||||||
@ -71,6 +72,9 @@ dependencies {
|
|||||||
// CLI deps
|
// CLI deps
|
||||||
compile project(path: ':core:cli', configuration: 'runtime')
|
compile project(path: ':core:cli', configuration: 'runtime')
|
||||||
|
|
||||||
|
// Core project deps (this is temporary)
|
||||||
|
compile project(':x-pack-elasticsearch:plugin:core')
|
||||||
|
|
||||||
// security deps
|
// security deps
|
||||||
compile project(path: ':modules:transport-netty4', configuration: 'runtime')
|
compile project(path: ':modules:transport-netty4', configuration: 'runtime')
|
||||||
compile 'com.unboundid:unboundid-ldapsdk:3.2.0'
|
compile 'com.unboundid:unboundid-ldapsdk:3.2.0'
|
||||||
|
@ -6,9 +6,16 @@ dependencies {
|
|||||||
|
|
||||||
archivesBaseName = 'x-pack-core'
|
archivesBaseName = 'x-pack-core'
|
||||||
|
|
||||||
|
compileJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes,-serial,-try,-unchecked"
|
||||||
|
//compileTestJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes,-serial,-try,-unchecked"
|
||||||
|
|
||||||
// TODO: enable this once we have tests
|
// TODO: enable this once we have tests
|
||||||
test.enabled=false
|
test.enabled=false
|
||||||
licenseHeaders.enabled = false
|
|
||||||
|
licenseHeaders {
|
||||||
|
approvedLicenses << 'BCrypt (BSD-like)'
|
||||||
|
additionalLicense 'BCRYP', 'BCrypt (BSD-like)', 'Copyright (c) 2006 Damien Miller <djm@mindrot.org>'
|
||||||
|
}
|
||||||
|
|
||||||
parent.bundlePlugin {
|
parent.bundlePlugin {
|
||||||
from jar
|
from jar
|
||||||
|
@ -9,8 +9,8 @@ import org.elasticsearch.common.Strings;
|
|||||||
import org.elasticsearch.common.logging.LoggerMessageFormat;
|
import org.elasticsearch.common.logging.LoggerMessageFormat;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.license.License.OperationMode;
|
import org.elasticsearch.license.License.OperationMode;
|
||||||
import org.elasticsearch.xpack.XPackPlugin;
|
import org.elasticsearch.xpack.XpackField;
|
||||||
import org.elasticsearch.xpack.monitoring.Monitoring;
|
import org.elasticsearch.xpack.monitoring.MonitoringField;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@ -29,35 +29,35 @@ public class XPackLicenseState {
|
|||||||
static final Map<String, String[]> EXPIRATION_MESSAGES;
|
static final Map<String, String[]> EXPIRATION_MESSAGES;
|
||||||
static {
|
static {
|
||||||
Map<String, String[]> messages = new LinkedHashMap<>();
|
Map<String, String[]> messages = new LinkedHashMap<>();
|
||||||
messages.put(XPackPlugin.SECURITY, new String[] {
|
messages.put(XpackField.SECURITY, new String[] {
|
||||||
"Cluster health, cluster stats and indices stats operations are blocked",
|
"Cluster health, cluster stats and indices stats operations are blocked",
|
||||||
"All data operations (read and write) continue to work"
|
"All data operations (read and write) continue to work"
|
||||||
});
|
});
|
||||||
messages.put(XPackPlugin.WATCHER, new String[] {
|
messages.put(XpackField.WATCHER, new String[] {
|
||||||
"PUT / GET watch APIs are disabled, DELETE watch API continues to work",
|
"PUT / GET watch APIs are disabled, DELETE watch API continues to work",
|
||||||
"Watches execute and write to the history",
|
"Watches execute and write to the history",
|
||||||
"The actions of the watches don't execute"
|
"The actions of the watches don't execute"
|
||||||
});
|
});
|
||||||
messages.put(XPackPlugin.MONITORING, new String[] {
|
messages.put(XpackField.MONITORING, new String[] {
|
||||||
"The agent will stop collecting cluster and indices metrics",
|
"The agent will stop collecting cluster and indices metrics",
|
||||||
"The agent will stop automatically cleaning indices older than [xpack.monitoring.history.duration]"
|
"The agent will stop automatically cleaning indices older than [xpack.monitoring.history.duration]"
|
||||||
});
|
});
|
||||||
messages.put(XPackPlugin.GRAPH, new String[] {
|
messages.put(XpackField.GRAPH, new String[] {
|
||||||
"Graph explore APIs are disabled"
|
"Graph explore APIs are disabled"
|
||||||
});
|
});
|
||||||
messages.put(XPackPlugin.MACHINE_LEARNING, new String[] {
|
messages.put(XpackField.MACHINE_LEARNING, new String[] {
|
||||||
"Machine learning APIs are disabled"
|
"Machine learning APIs are disabled"
|
||||||
});
|
});
|
||||||
messages.put(XPackPlugin.LOGSTASH, new String[] {
|
messages.put(XpackField.LOGSTASH, new String[] {
|
||||||
"Logstash will continue to poll centrally-managed pipelines"
|
"Logstash will continue to poll centrally-managed pipelines"
|
||||||
});
|
});
|
||||||
messages.put(XPackPlugin.DEPRECATION, new String[] {
|
messages.put(XpackField.DEPRECATION, new String[] {
|
||||||
"Deprecation APIs are disabled"
|
"Deprecation APIs are disabled"
|
||||||
});
|
});
|
||||||
messages.put(XPackPlugin.UPGRADE, new String[] {
|
messages.put(XpackField.UPGRADE, new String[] {
|
||||||
"Upgrade API is disabled"
|
"Upgrade API is disabled"
|
||||||
});
|
});
|
||||||
messages.put(XPackPlugin.SQL, new String[] {
|
messages.put(XpackField.SQL, new String[] {
|
||||||
"SQL support is disabled"
|
"SQL support is disabled"
|
||||||
});
|
});
|
||||||
EXPIRATION_MESSAGES = Collections.unmodifiableMap(messages);
|
EXPIRATION_MESSAGES = Collections.unmodifiableMap(messages);
|
||||||
@ -70,13 +70,13 @@ public class XPackLicenseState {
|
|||||||
static final Map<String, BiFunction<OperationMode, OperationMode, String[]>> ACKNOWLEDGMENT_MESSAGES;
|
static final Map<String, BiFunction<OperationMode, OperationMode, String[]>> ACKNOWLEDGMENT_MESSAGES;
|
||||||
static {
|
static {
|
||||||
Map<String, BiFunction<OperationMode, OperationMode, String[]>> messages = new LinkedHashMap<>();
|
Map<String, BiFunction<OperationMode, OperationMode, String[]>> messages = new LinkedHashMap<>();
|
||||||
messages.put(XPackPlugin.SECURITY, XPackLicenseState::securityAcknowledgementMessages);
|
messages.put(XpackField.SECURITY, XPackLicenseState::securityAcknowledgementMessages);
|
||||||
messages.put(XPackPlugin.WATCHER, XPackLicenseState::watcherAcknowledgementMessages);
|
messages.put(XpackField.WATCHER, XPackLicenseState::watcherAcknowledgementMessages);
|
||||||
messages.put(XPackPlugin.MONITORING, XPackLicenseState::monitoringAcknowledgementMessages);
|
messages.put(XpackField.MONITORING, XPackLicenseState::monitoringAcknowledgementMessages);
|
||||||
messages.put(XPackPlugin.GRAPH, XPackLicenseState::graphAcknowledgementMessages);
|
messages.put(XpackField.GRAPH, XPackLicenseState::graphAcknowledgementMessages);
|
||||||
messages.put(XPackPlugin.MACHINE_LEARNING, XPackLicenseState::machineLearningAcknowledgementMessages);
|
messages.put(XpackField.MACHINE_LEARNING, XPackLicenseState::machineLearningAcknowledgementMessages);
|
||||||
messages.put(XPackPlugin.LOGSTASH, XPackLicenseState::logstashAcknowledgementMessages);
|
messages.put(XpackField.LOGSTASH, XPackLicenseState::logstashAcknowledgementMessages);
|
||||||
messages.put(XPackPlugin.SQL, XPackLicenseState::sqlAcknowledgementMessages);
|
messages.put(XpackField.SQL, XPackLicenseState::sqlAcknowledgementMessages);
|
||||||
ACKNOWLEDGMENT_MESSAGES = Collections.unmodifiableMap(messages);
|
ACKNOWLEDGMENT_MESSAGES = Collections.unmodifiableMap(messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ public class XPackLicenseState {
|
|||||||
return new String[] {
|
return new String[] {
|
||||||
"The following X-Pack security functionality will be disabled: authentication, authorization, " +
|
"The following X-Pack security functionality will be disabled: authentication, authorization, " +
|
||||||
"ip filtering, and auditing. Please restart your node after applying the license.",
|
"ip filtering, and auditing. Please restart your node after applying the license.",
|
||||||
"Field and document level access control will be disabled.",
|
"ThrottlerField and document level access control will be disabled.",
|
||||||
"Custom realms will be ignored."
|
"Custom realms will be ignored."
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -104,7 +104,7 @@ public class XPackLicenseState {
|
|||||||
case TRIAL:
|
case TRIAL:
|
||||||
case PLATINUM:
|
case PLATINUM:
|
||||||
return new String[] {
|
return new String[] {
|
||||||
"Field and document level access control will be disabled.",
|
"ThrottlerField and document level access control will be disabled.",
|
||||||
"Custom realms will be ignored."
|
"Custom realms will be ignored."
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -119,7 +119,7 @@ public class XPackLicenseState {
|
|||||||
return new String[] {
|
return new String[] {
|
||||||
"Authentication will be limited to the native realms.",
|
"Authentication will be limited to the native realms.",
|
||||||
"IP filtering and auditing will be disabled.",
|
"IP filtering and auditing will be disabled.",
|
||||||
"Field and document level access control will be disabled.",
|
"ThrottlerField and document level access control will be disabled.",
|
||||||
"Custom realms will be ignored."
|
"Custom realms will be ignored."
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -159,7 +159,7 @@ public class XPackLicenseState {
|
|||||||
newMode, newMode, newMode),
|
newMode, newMode, newMode),
|
||||||
LoggerMessageFormat.format(
|
LoggerMessageFormat.format(
|
||||||
"Automatic index cleanup is locked to {} days for clusters with [{}] license.",
|
"Automatic index cleanup is locked to {} days for clusters with [{}] license.",
|
||||||
Monitoring.HISTORY_DURATION.getDefault(Settings.EMPTY).days(), newMode)
|
MonitoringField.HISTORY_DURATION.getDefault(Settings.EMPTY).days(), newMode)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -307,7 +307,7 @@ public class XPackLicenseState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if Document Level Security (DLS) and Field Level Security (FLS) should be enabled.
|
* Determine if Document Level Security (DLS) and ThrottlerField Level Security (FLS) should be enabled.
|
||||||
* <p>
|
* <p>
|
||||||
* DLS and FLS are only disabled when the mode is not:
|
* DLS and FLS are only disabled when the mode is not:
|
||||||
* <ul>
|
* <ul>
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.settings.Settings;
|
||||||
|
|
||||||
|
public interface XPackClientActionPlugin {
|
||||||
|
|
||||||
|
static boolean isTribeNode(Settings settings) {
|
||||||
|
return settings.getGroups("tribe", true).isEmpty() == false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean isTribeClientNode(Settings settings) {
|
||||||
|
return settings.get("tribe.name") != null;
|
||||||
|
}
|
||||||
|
}
|
@ -8,7 +8,7 @@ package org.elasticsearch.xpack;
|
|||||||
import org.elasticsearch.common.network.NetworkModule;
|
import org.elasticsearch.common.network.NetworkModule;
|
||||||
import org.elasticsearch.common.settings.Setting;
|
import org.elasticsearch.common.settings.Setting;
|
||||||
import org.elasticsearch.common.settings.Setting.Property;
|
import org.elasticsearch.common.settings.Setting.Property;
|
||||||
import org.elasticsearch.xpack.security.Security;
|
import org.elasticsearch.xpack.security.SecurityField;
|
||||||
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
import org.elasticsearch.xpack.ssl.SSLClientAuth;
|
||||||
import org.elasticsearch.xpack.ssl.SSLConfigurationSettings;
|
import org.elasticsearch.xpack.ssl.SSLConfigurationSettings;
|
||||||
import org.elasticsearch.xpack.ssl.VerificationMode;
|
import org.elasticsearch.xpack.ssl.VerificationMode;
|
||||||
@ -30,7 +30,7 @@ public class XPackSettings {
|
|||||||
/** Setting for enabling or disabling monitoring. Defaults to true if not a tribe node. */
|
/** Setting for enabling or disabling monitoring. Defaults to true if not a tribe node. */
|
||||||
public static final Setting<Boolean> MONITORING_ENABLED = Setting.boolSetting("xpack.monitoring.enabled",
|
public static final Setting<Boolean> MONITORING_ENABLED = Setting.boolSetting("xpack.monitoring.enabled",
|
||||||
// By default, monitoring is disabled on tribe nodes
|
// By default, monitoring is disabled on tribe nodes
|
||||||
s -> String.valueOf(XPackPlugin.isTribeNode(s) == false && XPackPlugin.isTribeClientNode(s) == false),
|
s -> String.valueOf(XPackClientActionPlugin.isTribeNode(s) == false && XPackClientActionPlugin.isTribeClientNode(s) == false),
|
||||||
Setting.Property.NodeScope);
|
Setting.Property.NodeScope);
|
||||||
|
|
||||||
/** Setting for enabling or disabling watcher. Defaults to true. */
|
/** Setting for enabling or disabling watcher. Defaults to true. */
|
||||||
@ -116,11 +116,11 @@ public class XPackSettings {
|
|||||||
private static final SSLConfigurationSettings GLOBAL_SSL = SSLConfigurationSettings.withPrefix(GLOBAL_SSL_PREFIX);
|
private static final SSLConfigurationSettings GLOBAL_SSL = SSLConfigurationSettings.withPrefix(GLOBAL_SSL_PREFIX);
|
||||||
|
|
||||||
// http specific settings
|
// http specific settings
|
||||||
public static final String HTTP_SSL_PREFIX = Security.setting("http.ssl.");
|
public static final String HTTP_SSL_PREFIX = SecurityField.setting("http.ssl.");
|
||||||
private static final SSLConfigurationSettings HTTP_SSL = SSLConfigurationSettings.withPrefix(HTTP_SSL_PREFIX);
|
private static final SSLConfigurationSettings HTTP_SSL = SSLConfigurationSettings.withPrefix(HTTP_SSL_PREFIX);
|
||||||
|
|
||||||
// transport specific settings
|
// transport specific settings
|
||||||
public static final String TRANSPORT_SSL_PREFIX = Security.setting("transport.ssl.");
|
public static final String TRANSPORT_SSL_PREFIX = SecurityField.setting("transport.ssl.");
|
||||||
private static final SSLConfigurationSettings TRANSPORT_SSL = SSLConfigurationSettings.withPrefix(TRANSPORT_SSL_PREFIX);
|
private static final SSLConfigurationSettings TRANSPORT_SSL = SSLConfigurationSettings.withPrefix(TRANSPORT_SSL_PREFIX);
|
||||||
|
|
||||||
/** Returns all settings created in {@link XPackSettings}. */
|
/** Returns all settings created in {@link XPackSettings}. */
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
public final class XpackField {
|
||||||
|
// These should be moved back to XPackPlugin once its moved to common
|
||||||
|
public static final String NAME = "x-pack";
|
||||||
|
/** Name constant for the security feature. */
|
||||||
|
public static final String SECURITY = "security";
|
||||||
|
/** Name constant for the monitoring feature. */
|
||||||
|
public static final String MONITORING = "monitoring";
|
||||||
|
/** Name constant for the watcher feature. */
|
||||||
|
public static final String WATCHER = "watcher";
|
||||||
|
/** Name constant for the graph feature. */
|
||||||
|
public static final String GRAPH = "graph";
|
||||||
|
/** Name constant for the machine learning feature. */
|
||||||
|
public static final String MACHINE_LEARNING = "ml";
|
||||||
|
/** Name constant for the Logstash feature. */
|
||||||
|
public static final String LOGSTASH = "logstash";
|
||||||
|
/** Name constant for the Deprecation API feature. */
|
||||||
|
public static final String DEPRECATION = "deprecation";
|
||||||
|
/** Name constant for the upgrade feature. */
|
||||||
|
public static final String UPGRADE = "upgrade";
|
||||||
|
// inside of YAML settings we still use xpack do not having handle issues with dashes
|
||||||
|
public static final String SETTINGS_NAME = "xpack";
|
||||||
|
/** Name constant for the sql feature. */
|
||||||
|
public static final String SQL = "sql";
|
||||||
|
|
||||||
|
private XpackField() {}
|
||||||
|
|
||||||
|
public static String featureSettingPrefix(String featureName) {
|
||||||
|
return XpackField.SETTINGS_NAME + "." + featureName;
|
||||||
|
}
|
||||||
|
}
|
@ -6,42 +6,23 @@
|
|||||||
package org.elasticsearch.xpack.deprecation;
|
package org.elasticsearch.xpack.deprecation;
|
||||||
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.action.IndicesRequest;
|
import org.elasticsearch.action.IndicesRequest;
|
||||||
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
|
import org.elasticsearch.action.admin.cluster.node.info.NodeInfo;
|
||||||
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequest;
|
|
||||||
import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse;
|
|
||||||
import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
|
import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
|
||||||
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsRequest;
|
|
||||||
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
|
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.IndicesOptions;
|
import org.elasticsearch.action.support.IndicesOptions;
|
||||||
import org.elasticsearch.action.support.master.MasterNodeReadOperationRequestBuilder;
|
import org.elasticsearch.action.support.master.MasterNodeReadOperationRequestBuilder;
|
||||||
import org.elasticsearch.action.support.master.MasterNodeReadRequest;
|
import org.elasticsearch.action.support.master.MasterNodeReadRequest;
|
||||||
import org.elasticsearch.action.support.master.TransportMasterNodeReadAction;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.client.node.NodeClient;
|
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
import org.elasticsearch.cluster.ClusterState;
|
||||||
import org.elasticsearch.cluster.block.ClusterBlockException;
|
|
||||||
import org.elasticsearch.cluster.block.ClusterBlockLevel;
|
|
||||||
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
import org.elasticsearch.cluster.metadata.IndexMetaData;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.license.LicenseUtils;
|
|
||||||
import org.elasticsearch.license.XPackLicenseState;
|
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.XPackPlugin;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -49,16 +30,12 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||||
import static org.elasticsearch.xpack.ClientHelper.DEPRECATION_ORIGIN;
|
|
||||||
import static org.elasticsearch.xpack.ClientHelper.executeAsyncWithOrigin;
|
|
||||||
import static org.elasticsearch.xpack.deprecation.DeprecationChecks.CLUSTER_SETTINGS_CHECKS;
|
|
||||||
import static org.elasticsearch.xpack.deprecation.DeprecationChecks.INDEX_SETTINGS_CHECKS;
|
|
||||||
import static org.elasticsearch.xpack.deprecation.DeprecationChecks.NODE_SETTINGS_CHECKS;
|
|
||||||
import static org.elasticsearch.xpack.deprecation.DeprecationChecks.filterChecks;
|
|
||||||
|
|
||||||
public class DeprecationInfoAction extends Action<DeprecationInfoAction.Request,
|
public class DeprecationInfoAction extends Action<DeprecationInfoAction.Request,
|
||||||
DeprecationInfoAction.Response, DeprecationInfoAction.RequestBuilder> {
|
DeprecationInfoAction.Response, DeprecationInfoAction.RequestBuilder> {
|
||||||
@ -70,6 +47,18 @@ public class DeprecationInfoAction extends Action<DeprecationInfoAction.Request,
|
|||||||
super(NAME);
|
super(NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* helper utility function to reduce repeat of running a specific {@link Set} of checks.
|
||||||
|
*
|
||||||
|
* @param checks The functional checks to execute using the mapper function
|
||||||
|
* @param mapper The function that executes the lambda check with the appropriate arguments
|
||||||
|
* @param <T> The signature of the check (BiFunction, Function, including the appropriate arguments)
|
||||||
|
* @return The list of {@link DeprecationIssue} that were found in the cluster
|
||||||
|
*/
|
||||||
|
static <T> List<DeprecationIssue> filterChecks(List<T> checks, Function<T, DeprecationIssue> mapper) {
|
||||||
|
return checks.stream().map(mapper).filter(Objects::nonNull).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
return new RequestBuilder(client, this);
|
return new RequestBuilder(client, this);
|
||||||
@ -276,69 +265,4 @@ public class DeprecationInfoAction extends Action<DeprecationInfoAction.Request,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends TransportMasterNodeReadAction<Request, Response> {
|
|
||||||
|
|
||||||
private final XPackLicenseState licenseState;
|
|
||||||
private final NodeClient client;
|
|
||||||
private final IndexNameExpressionResolver indexNameExpressionResolver;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, TransportService transportService, ClusterService clusterService,
|
|
||||||
ThreadPool threadPool, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
XPackLicenseState licenseState, NodeClient client) {
|
|
||||||
super(settings, DeprecationInfoAction.NAME, transportService, clusterService, threadPool, actionFilters,
|
|
||||||
Request::new, indexNameExpressionResolver);
|
|
||||||
this.licenseState = licenseState;
|
|
||||||
this.client = client;
|
|
||||||
this.indexNameExpressionResolver = indexNameExpressionResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String executor() {
|
|
||||||
return ThreadPool.Names.GENERIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Response newResponse() {
|
|
||||||
return new Response();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ClusterBlockException checkBlock(Request request, ClusterState state) {
|
|
||||||
// Cluster is not affected but we look up repositories in metadata
|
|
||||||
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected final void masterOperation(final Request request, ClusterState state, final ActionListener<Response> listener) {
|
|
||||||
if (licenseState.isDeprecationAllowed()) {
|
|
||||||
NodesInfoRequest nodesInfoRequest = new NodesInfoRequest("_local").settings(true).plugins(true);
|
|
||||||
NodesStatsRequest nodesStatsRequest = new NodesStatsRequest("_local").fs(true);
|
|
||||||
|
|
||||||
final ThreadContext threadContext = client.threadPool().getThreadContext();
|
|
||||||
executeAsyncWithOrigin(threadContext, DEPRECATION_ORIGIN, nodesInfoRequest, ActionListener.<NodesInfoResponse>wrap(
|
|
||||||
nodesInfoResponse -> {
|
|
||||||
if (nodesInfoResponse.hasFailures()) {
|
|
||||||
throw nodesInfoResponse.failures().get(0);
|
|
||||||
}
|
|
||||||
executeAsyncWithOrigin(threadContext, DEPRECATION_ORIGIN, nodesStatsRequest,
|
|
||||||
ActionListener.<NodesStatsResponse>wrap(
|
|
||||||
nodesStatsResponse -> {
|
|
||||||
if (nodesStatsResponse.hasFailures()) {
|
|
||||||
throw nodesStatsResponse.failures().get(0);
|
|
||||||
}
|
|
||||||
listener.onResponse(Response.from(nodesInfoResponse.getNodes(),
|
|
||||||
nodesStatsResponse.getNodes(), state, indexNameExpressionResolver,
|
|
||||||
request.indices(), request.indicesOptions(),
|
|
||||||
CLUSTER_SETTINGS_CHECKS, NODE_SETTINGS_CHECKS,
|
|
||||||
INDEX_SETTINGS_CHECKS));
|
|
||||||
}, listener::onFailure),
|
|
||||||
client.admin().cluster()::nodesStats);
|
|
||||||
}, listener::onFailure), client.admin().cluster()::nodesInfo);
|
|
||||||
} else {
|
|
||||||
listener.onFailure(LicenseUtils.newComplianceException(XPackPlugin.DEPRECATION));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml;
|
||||||
|
|
||||||
|
public final class MLMetadataField {
|
||||||
|
|
||||||
|
public static final String TYPE = "ml";
|
||||||
|
|
||||||
|
private MLMetadataField() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Namespaces the task ids for datafeeds.
|
||||||
|
* A job id can be used as a datafeed id, because they are stored separately in cluster state.
|
||||||
|
*/
|
||||||
|
public static String datafeedTaskId(String datafeedId) {
|
||||||
|
return "datafeed-" + datafeedId;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.settings.Setting;
|
||||||
|
import org.elasticsearch.common.unit.ByteSizeValue;
|
||||||
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
|
|
||||||
|
public interface MachineLearningClientActionPlugin {
|
||||||
|
|
||||||
|
Setting<ByteSizeValue> MAX_MODEL_MEMORY_LIMIT =
|
||||||
|
Setting.memorySizeSetting("xpack.ml.max_model_memory_limit", new ByteSizeValue(0),
|
||||||
|
Setting.Property.Dynamic, Setting.Property.NodeScope);
|
||||||
|
|
||||||
|
TimeValue STATE_PERSIST_RESTORE_TIMEOUT = TimeValue.timeValueMinutes(30);
|
||||||
|
}
|
@ -9,18 +9,16 @@ import org.elasticsearch.action.ActionResponse;
|
|||||||
import org.elasticsearch.client.Client;
|
import org.elasticsearch.client.Client;
|
||||||
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
import org.elasticsearch.common.util.concurrent.ThreadContext;
|
||||||
import org.elasticsearch.common.util.set.Sets;
|
import org.elasticsearch.common.util.set.Sets;
|
||||||
|
import org.elasticsearch.xpack.ClientHelper;
|
||||||
import org.elasticsearch.xpack.ml.datafeed.DatafeedConfig;
|
import org.elasticsearch.xpack.ml.datafeed.DatafeedConfig;
|
||||||
import org.elasticsearch.xpack.security.authc.Authentication;
|
import org.elasticsearch.xpack.security.authc.AuthenticationField;
|
||||||
import org.elasticsearch.xpack.security.authc.AuthenticationService;
|
import org.elasticsearch.xpack.security.authc.AuthenticationServiceField;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.elasticsearch.xpack.ClientHelper.ML_ORIGIN;
|
|
||||||
import static org.elasticsearch.xpack.ClientHelper.stashWithOrigin;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper class for actions which decides if we should run via the _xpack user and set ML as origin
|
* A helper class for actions which decides if we should run via the _xpack user and set ML as origin
|
||||||
* or if we should use the run_as functionality by setting the correct headers
|
* or if we should use the run_as functionality by setting the correct headers
|
||||||
@ -30,8 +28,8 @@ public class MlClientHelper {
|
|||||||
/**
|
/**
|
||||||
* List of headers that are related to security
|
* List of headers that are related to security
|
||||||
*/
|
*/
|
||||||
public static final Set<String> SECURITY_HEADER_FILTERS = Sets.newHashSet(AuthenticationService.RUN_AS_USER_HEADER,
|
public static final Set<String> SECURITY_HEADER_FILTERS = Sets.newHashSet(AuthenticationServiceField.RUN_AS_USER_HEADER,
|
||||||
Authentication.AUTHENTICATION_KEY);
|
AuthenticationField.AUTHENTICATION_KEY);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a client operation and return the response, try to run a datafeed search with least privileges, when headers exist
|
* Execute a client operation and return the response, try to run a datafeed search with least privileges, when headers exist
|
||||||
@ -56,7 +54,8 @@ public class MlClientHelper {
|
|||||||
public static <T extends ActionResponse> T execute(Map<String, String> headers, Client client, Supplier<T> supplier) {
|
public static <T extends ActionResponse> T execute(Map<String, String> headers, Client client, Supplier<T> supplier) {
|
||||||
// no headers, we will have to use the xpack internal user for our execution by specifying the ml origin
|
// no headers, we will have to use the xpack internal user for our execution by specifying the ml origin
|
||||||
if (headers == null || headers.isEmpty()) {
|
if (headers == null || headers.isEmpty()) {
|
||||||
try (ThreadContext.StoredContext ignore = stashWithOrigin(client.threadPool().getThreadContext(), ML_ORIGIN)) {
|
try (ThreadContext.StoredContext ignore = ClientHelper.stashWithOrigin(client.threadPool().getThreadContext(),
|
||||||
|
ClientHelper.ML_ORIGIN)) {
|
||||||
return supplier.get();
|
return supplier.get();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
@ -56,7 +56,6 @@ public class MlMetadata implements MetaData.Custom {
|
|||||||
private static final ParseField JOBS_FIELD = new ParseField("jobs");
|
private static final ParseField JOBS_FIELD = new ParseField("jobs");
|
||||||
private static final ParseField DATAFEEDS_FIELD = new ParseField("datafeeds");
|
private static final ParseField DATAFEEDS_FIELD = new ParseField("datafeeds");
|
||||||
|
|
||||||
public static final String TYPE = "ml";
|
|
||||||
public static final MlMetadata EMPTY_METADATA = new MlMetadata(Collections.emptySortedMap(), Collections.emptySortedMap());
|
public static final MlMetadata EMPTY_METADATA = new MlMetadata(Collections.emptySortedMap(), Collections.emptySortedMap());
|
||||||
// This parser follows the pattern that metadata is parsed leniently (to allow for enhancements)
|
// This parser follows the pattern that metadata is parsed leniently (to allow for enhancements)
|
||||||
public static final ObjectParser<Builder, Void> METADATA_PARSER = new ObjectParser<>("ml_metadata", true, Builder::new);
|
public static final ObjectParser<Builder, Void> METADATA_PARSER = new ObjectParser<>("ml_metadata", true, Builder::new);
|
||||||
@ -118,7 +117,7 @@ public class MlMetadata implements MetaData.Custom {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWriteableName() {
|
public String getWriteableName() {
|
||||||
return TYPE;
|
return MLMetadataField.TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -212,7 +211,7 @@ public class MlMetadata implements MetaData.Custom {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWriteableName() {
|
public String getWriteableName() {
|
||||||
return TYPE;
|
return MLMetadataField.TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Diff<Job> readJobDiffFrom(StreamInput in) throws IOException {
|
static Diff<Job> readJobDiffFrom(StreamInput in) throws IOException {
|
||||||
@ -361,7 +360,7 @@ public class MlMetadata implements MetaData.Custom {
|
|||||||
|
|
||||||
private void checkDatafeedIsStopped(Supplier<String> msg, String datafeedId, PersistentTasksCustomMetaData persistentTasks) {
|
private void checkDatafeedIsStopped(Supplier<String> msg, String datafeedId, PersistentTasksCustomMetaData persistentTasks) {
|
||||||
if (persistentTasks != null) {
|
if (persistentTasks != null) {
|
||||||
if (persistentTasks.getTask(datafeedTaskId(datafeedId)) != null) {
|
if (persistentTasks.getTask(MLMetadataField.datafeedTaskId(datafeedId)) != null) {
|
||||||
throw ExceptionsHelper.conflictStatusException(msg.get());
|
throw ExceptionsHelper.conflictStatusException(msg.get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -435,20 +434,12 @@ public class MlMetadata implements MetaData.Custom {
|
|||||||
return tasks.getTask(jobTaskId(jobId));
|
return tasks.getTask(jobTaskId(jobId));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Namespaces the task ids for datafeeds.
|
|
||||||
* A job id can be used as a datafeed id, because they are stored separately in cluster state.
|
|
||||||
*/
|
|
||||||
public static String datafeedTaskId(String datafeedId) {
|
|
||||||
return "datafeed-" + datafeedId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static PersistentTask<?> getDatafeedTask(String datafeedId, @Nullable PersistentTasksCustomMetaData tasks) {
|
public static PersistentTask<?> getDatafeedTask(String datafeedId, @Nullable PersistentTasksCustomMetaData tasks) {
|
||||||
if (tasks == null) {
|
if (tasks == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return tasks.getTask(datafeedTaskId(datafeedId));
|
return tasks.getTask(MLMetadataField.datafeedTaskId(datafeedId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JobState getJobState(String jobId, @Nullable PersistentTasksCustomMetaData tasks) {
|
public static JobState getJobState(String jobId, @Nullable PersistentTasksCustomMetaData tasks) {
|
@ -0,0 +1,272 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.Version;
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
|
import org.elasticsearch.action.support.tasks.BaseTasksRequest;
|
||||||
|
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
import org.elasticsearch.common.ParseField;
|
||||||
|
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.ObjectParser;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.tasks.Task;
|
||||||
|
import org.elasticsearch.xpack.ml.MachineLearningClientActionPlugin;
|
||||||
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class CloseJobAction extends Action<CloseJobAction.Request, CloseJobAction.Response, CloseJobAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final CloseJobAction INSTANCE = new CloseJobAction();
|
||||||
|
public static final String NAME = "cluster:admin/xpack/ml/job/close";
|
||||||
|
|
||||||
|
private CloseJobAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends BaseTasksRequest<Request> implements ToXContentObject {
|
||||||
|
|
||||||
|
public static final ParseField TIMEOUT = new ParseField("timeout");
|
||||||
|
public static final ParseField FORCE = new ParseField("force");
|
||||||
|
public static final ParseField ALLOW_NO_JOBS = new ParseField("allow_no_jobs");
|
||||||
|
public static ObjectParser<Request, Void> PARSER = new ObjectParser<>(NAME, Request::new);
|
||||||
|
|
||||||
|
static {
|
||||||
|
PARSER.declareString(Request::setJobId, Job.ID);
|
||||||
|
PARSER.declareString((request, val) ->
|
||||||
|
request.setCloseTimeout(TimeValue.parseTimeValue(val, TIMEOUT.getPreferredName())), TIMEOUT);
|
||||||
|
PARSER.declareBoolean(Request::setForce, FORCE);
|
||||||
|
PARSER.declareBoolean(Request::setAllowNoJobs, ALLOW_NO_JOBS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Request parseRequest(String jobId, XContentParser parser) {
|
||||||
|
Request request = PARSER.apply(parser, null);
|
||||||
|
if (jobId != null) {
|
||||||
|
request.setJobId(jobId);
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String jobId;
|
||||||
|
private boolean force = false;
|
||||||
|
private boolean allowNoJobs = true;
|
||||||
|
// A big state can take a while to persist. For symmetry with the _open endpoint any
|
||||||
|
// changes here should be reflected there too.
|
||||||
|
private TimeValue timeout = MachineLearningClientActionPlugin.STATE_PERSIST_RESTORE_TIMEOUT;
|
||||||
|
|
||||||
|
private String[] openJobIds;
|
||||||
|
|
||||||
|
private boolean local;
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
openJobIds = new String[] {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Request(String jobId) {
|
||||||
|
this();
|
||||||
|
this.jobId = jobId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJobId() {
|
||||||
|
return jobId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJobId(String jobId) {
|
||||||
|
this.jobId = jobId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeValue getCloseTimeout() {
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCloseTimeout(TimeValue timeout) {
|
||||||
|
this.timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isForce() {
|
||||||
|
return force;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForce(boolean force) {
|
||||||
|
this.force = force;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean allowNoJobs() {
|
||||||
|
return allowNoJobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowNoJobs(boolean allowNoJobs) {
|
||||||
|
this.allowNoJobs = allowNoJobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLocal() { return local; }
|
||||||
|
|
||||||
|
public void setLocal(boolean local) {
|
||||||
|
this.local = local;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getOpenJobIds() { return openJobIds; }
|
||||||
|
|
||||||
|
public void setOpenJobIds(String [] openJobIds) {
|
||||||
|
this.openJobIds = openJobIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
jobId = in.readString();
|
||||||
|
timeout = new TimeValue(in);
|
||||||
|
force = in.readBoolean();
|
||||||
|
openJobIds = in.readStringArray();
|
||||||
|
local = in.readBoolean();
|
||||||
|
if (in.getVersion().onOrAfter(Version.V_6_1_0)) {
|
||||||
|
allowNoJobs = in.readBoolean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeString(jobId);
|
||||||
|
timeout.writeTo(out);
|
||||||
|
out.writeBoolean(force);
|
||||||
|
out.writeStringArray(openJobIds);
|
||||||
|
out.writeBoolean(local);
|
||||||
|
if (out.getVersion().onOrAfter(Version.V_6_1_0)) {
|
||||||
|
out.writeBoolean(allowNoJobs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean match(Task task) {
|
||||||
|
for (String id : openJobIds) {
|
||||||
|
if (OpenJobAction.JobTaskMatcher.match(task, id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
// openJobIds are excluded
|
||||||
|
builder.startObject();
|
||||||
|
builder.field(Job.ID.getPreferredName(), jobId);
|
||||||
|
builder.field(TIMEOUT.getPreferredName(), timeout.getStringRep());
|
||||||
|
builder.field(FORCE.getPreferredName(), force);
|
||||||
|
builder.field(ALLOW_NO_JOBS.getPreferredName(), allowNoJobs);
|
||||||
|
builder.endObject();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
// openJobIds are excluded
|
||||||
|
return Objects.hash(jobId, timeout, force, allowNoJobs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || obj.getClass() != getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Request other = (Request) obj;
|
||||||
|
// openJobIds are excluded
|
||||||
|
return Objects.equals(jobId, other.jobId) &&
|
||||||
|
Objects.equals(timeout, other.timeout) &&
|
||||||
|
Objects.equals(force, other.force) &&
|
||||||
|
Objects.equals(allowNoJobs, other.allowNoJobs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
RequestBuilder(ElasticsearchClient client, CloseJobAction action) {
|
||||||
|
super(client, action, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends BaseTasksResponse implements Writeable, ToXContentObject {
|
||||||
|
|
||||||
|
private boolean closed;
|
||||||
|
|
||||||
|
Response() {
|
||||||
|
super(null, null);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Response(StreamInput in) throws IOException {
|
||||||
|
super(null, null);
|
||||||
|
readFrom(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
Response(boolean closed) {
|
||||||
|
super(null, null);
|
||||||
|
this.closed = closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClosed() {
|
||||||
|
return closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
closed = in.readBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeBoolean(closed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
builder.field("closed", closed);
|
||||||
|
builder.endObject();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Response response = (Response) o;
|
||||||
|
return closed == response.closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(closed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -5,40 +5,20 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.ResourceNotFoundException;
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.bulk.BulkAction;
|
|
||||||
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
|
||||||
import org.elasticsearch.action.bulk.BulkResponse;
|
|
||||||
import org.elasticsearch.action.delete.DeleteRequest;
|
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.HandledTransportAction;
|
|
||||||
import org.elasticsearch.action.support.WriteRequest;
|
|
||||||
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
||||||
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
import org.elasticsearch.client.Client;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.rest.RestStatus;
|
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.MlMetaIndex;
|
|
||||||
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static org.elasticsearch.xpack.ClientHelper.ML_ORIGIN;
|
|
||||||
import static org.elasticsearch.xpack.ClientHelper.executeAsyncWithOrigin;
|
|
||||||
|
|
||||||
public class DeleteCalendarAction extends Action<DeleteCalendarAction.Request, DeleteCalendarAction.Response,
|
public class DeleteCalendarAction extends Action<DeleteCalendarAction.Request, DeleteCalendarAction.Response,
|
||||||
DeleteCalendarAction.RequestBuilder> {
|
DeleteCalendarAction.RequestBuilder> {
|
||||||
|
|
||||||
@ -138,47 +118,4 @@ public class DeleteCalendarAction extends Action<DeleteCalendarAction.Request, D
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends HandledTransportAction<DeleteCalendarAction.Request, DeleteCalendarAction.Response> {
|
|
||||||
|
|
||||||
private final Client client;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, ThreadPool threadPool,
|
|
||||||
TransportService transportService, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
Client client) {
|
|
||||||
super(settings, NAME, threadPool, transportService, actionFilters,
|
|
||||||
indexNameExpressionResolver, Request::new);
|
|
||||||
this.client = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(DeleteCalendarAction.Request request, ActionListener<DeleteCalendarAction.Response> listener) {
|
|
||||||
|
|
||||||
final String calendarId = request.getCalendarId();
|
|
||||||
|
|
||||||
DeleteRequest deleteRequest = new DeleteRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE, Calendar.documentId(calendarId));
|
|
||||||
|
|
||||||
BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
|
|
||||||
bulkRequestBuilder.add(deleteRequest);
|
|
||||||
bulkRequestBuilder.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
|
||||||
executeAsyncWithOrigin(client, ML_ORIGIN, BulkAction.INSTANCE, bulkRequestBuilder.request(),
|
|
||||||
new ActionListener<BulkResponse>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(BulkResponse bulkResponse) {
|
|
||||||
if (bulkResponse.getItems()[0].status() == RestStatus.NOT_FOUND) {
|
|
||||||
listener.onFailure(new ResourceNotFoundException("Could not delete calendar with ID [" + calendarId
|
|
||||||
+ "] because it does not exist"));
|
|
||||||
} else {
|
|
||||||
listener.onResponse(new Response(true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Exception e) {
|
|
||||||
listener.onFailure(ExceptionsHelper.serverError("Could not delete calendar with ID [" + calendarId + "]", e));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,144 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.Version;
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
|
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
import org.elasticsearch.common.ParseField;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContentFragment;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.xpack.ml.datafeed.DatafeedConfig;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class DeleteDatafeedAction extends Action<DeleteDatafeedAction.Request, DeleteDatafeedAction.Response,
|
||||||
|
DeleteDatafeedAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final DeleteDatafeedAction INSTANCE = new DeleteDatafeedAction();
|
||||||
|
public static final String NAME = "cluster:admin/xpack/ml/datafeeds/delete";
|
||||||
|
|
||||||
|
private DeleteDatafeedAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends AcknowledgedRequest<Request> implements ToXContentFragment {
|
||||||
|
|
||||||
|
public static final ParseField FORCE = new ParseField("force");
|
||||||
|
|
||||||
|
private String datafeedId;
|
||||||
|
private boolean force;
|
||||||
|
|
||||||
|
public Request(String datafeedId) {
|
||||||
|
this.datafeedId = ExceptionsHelper.requireNonNull(datafeedId, DatafeedConfig.ID.getPreferredName());
|
||||||
|
}
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDatafeedId() {
|
||||||
|
return datafeedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isForce() {
|
||||||
|
return force;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForce(boolean force) {
|
||||||
|
this.force = force;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
datafeedId = in.readString();
|
||||||
|
if (in.getVersion().onOrAfter(Version.V_5_5_0)) {
|
||||||
|
force = in.readBoolean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeString(datafeedId);
|
||||||
|
if (out.getVersion().onOrAfter(Version.V_5_5_0)) {
|
||||||
|
out.writeBoolean(force);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.field(DatafeedConfig.ID.getPreferredName(), datafeedId);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Request other = (Request) o;
|
||||||
|
return Objects.equals(datafeedId, other.datafeedId) && Objects.equals(force, other.force);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(datafeedId, force);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RequestBuilder extends MasterNodeOperationRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
public RequestBuilder(ElasticsearchClient client, DeleteDatafeedAction action) {
|
||||||
|
super(client, action, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends AcknowledgedResponse {
|
||||||
|
|
||||||
|
Response() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Response(boolean acknowledged) {
|
||||||
|
super(acknowledged);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
readAcknowledged(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
writeAcknowledged(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,38 +6,18 @@
|
|||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequest;
|
import org.elasticsearch.action.ActionRequest;
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.HandledTransportAction;
|
|
||||||
import org.elasticsearch.client.Client;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.MachineLearning;
|
|
||||||
import org.elasticsearch.xpack.ml.job.retention.ExpiredForecastsRemover;
|
|
||||||
import org.elasticsearch.xpack.ml.job.retention.ExpiredModelSnapshotsRemover;
|
|
||||||
import org.elasticsearch.xpack.ml.job.retention.ExpiredResultsRemover;
|
|
||||||
import org.elasticsearch.xpack.ml.job.retention.MlDataRemover;
|
|
||||||
import org.elasticsearch.xpack.ml.notifications.Auditor;
|
|
||||||
import org.elasticsearch.xpack.ml.utils.VolatileCursorIterator;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class DeleteExpiredDataAction extends Action<DeleteExpiredDataAction.Request, DeleteExpiredDataAction.Response,
|
public class DeleteExpiredDataAction extends Action<DeleteExpiredDataAction.Request, DeleteExpiredDataAction.Response,
|
||||||
@ -123,47 +103,4 @@ public class DeleteExpiredDataAction extends Action<DeleteExpiredDataAction.Requ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends HandledTransportAction<Request, Response> {
|
|
||||||
|
|
||||||
private final Client client;
|
|
||||||
private final ClusterService clusterService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, ThreadPool threadPool, TransportService transportService,
|
|
||||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
Client client, ClusterService clusterService) {
|
|
||||||
super(settings, NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver, Request::new);
|
|
||||||
this.client = client;
|
|
||||||
this.clusterService = clusterService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Request request, ActionListener<Response> listener) {
|
|
||||||
logger.info("Deleting expired data");
|
|
||||||
threadPool.executor(MachineLearning.UTILITY_THREAD_POOL_NAME).execute(() -> deleteExpiredData(listener));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteExpiredData(ActionListener<Response> listener) {
|
|
||||||
Auditor auditor = new Auditor(client, clusterService);
|
|
||||||
List<MlDataRemover> dataRemovers = Arrays.asList(
|
|
||||||
new ExpiredResultsRemover(client, clusterService, auditor),
|
|
||||||
new ExpiredForecastsRemover(client),
|
|
||||||
new ExpiredModelSnapshotsRemover(client, clusterService)
|
|
||||||
);
|
|
||||||
Iterator<MlDataRemover> dataRemoversIterator = new VolatileCursorIterator<>(dataRemovers);
|
|
||||||
deleteExpiredData(dataRemoversIterator, listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void deleteExpiredData(Iterator<MlDataRemover> mlDataRemoversIterator, ActionListener<Response> listener) {
|
|
||||||
if (mlDataRemoversIterator.hasNext()) {
|
|
||||||
MlDataRemover remover = mlDataRemoversIterator.next();
|
|
||||||
remover.remove(ActionListener.wrap(
|
|
||||||
booleanResponse -> deleteExpiredData(mlDataRemoversIterator, listener),
|
|
||||||
listener::onFailure));
|
|
||||||
} else {
|
|
||||||
logger.info("Completed deletion of expired data");
|
|
||||||
listener.onResponse(new Response(true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
|
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
import org.elasticsearch.common.ParseField;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
||||||
|
public class DeleteFilterAction extends Action<DeleteFilterAction.Request, DeleteFilterAction.Response, DeleteFilterAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final DeleteFilterAction INSTANCE = new DeleteFilterAction();
|
||||||
|
public static final String NAME = "cluster:admin/xpack/ml/filters/delete";
|
||||||
|
|
||||||
|
private DeleteFilterAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends AcknowledgedRequest<Request> {
|
||||||
|
|
||||||
|
public static final ParseField FILTER_ID = new ParseField("filter_id");
|
||||||
|
|
||||||
|
private String filterId;
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public Request(String filterId) {
|
||||||
|
this.filterId = ExceptionsHelper.requireNonNull(filterId, FILTER_ID.getPreferredName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilterId() {
|
||||||
|
return filterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
filterId = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeString(filterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(filterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Request other = (Request) obj;
|
||||||
|
return Objects.equals(filterId, other.filterId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RequestBuilder extends MasterNodeOperationRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
public RequestBuilder(ElasticsearchClient client, DeleteFilterAction action) {
|
||||||
|
super(client, action, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends AcknowledgedResponse {
|
||||||
|
|
||||||
|
public Response(boolean acknowledged) {
|
||||||
|
super(acknowledged);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
readAcknowledged(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
writeAcknowledged(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.Version;
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
|
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.tasks.Task;
|
||||||
|
import org.elasticsearch.tasks.TaskId;
|
||||||
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
|
import org.elasticsearch.xpack.ml.job.persistence.JobStorageDeletionTask;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class DeleteJobAction extends Action<DeleteJobAction.Request, DeleteJobAction.Response, DeleteJobAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final DeleteJobAction INSTANCE = new DeleteJobAction();
|
||||||
|
public static final String NAME = "cluster:admin/xpack/ml/job/delete";
|
||||||
|
|
||||||
|
private DeleteJobAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends AcknowledgedRequest<Request> {
|
||||||
|
|
||||||
|
private String jobId;
|
||||||
|
private boolean force;
|
||||||
|
|
||||||
|
public Request(String jobId) {
|
||||||
|
this.jobId = ExceptionsHelper.requireNonNull(jobId, Job.ID.getPreferredName());
|
||||||
|
}
|
||||||
|
|
||||||
|
Request() {}
|
||||||
|
|
||||||
|
public String getJobId() {
|
||||||
|
return jobId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJobId(String jobId) {
|
||||||
|
this.jobId = jobId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isForce() {
|
||||||
|
return force;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForce(boolean force) {
|
||||||
|
this.force = force;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Task createTask(long id, String type, String action, TaskId parentTaskId) {
|
||||||
|
return new JobStorageDeletionTask(id, type, action, "delete-job-" + jobId, parentTaskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
jobId = in.readString();
|
||||||
|
if (in.getVersion().onOrAfter(Version.V_5_5_0)) {
|
||||||
|
force = in.readBoolean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeString(jobId);
|
||||||
|
if (out.getVersion().onOrAfter(Version.V_5_5_0)) {
|
||||||
|
out.writeBoolean(force);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(jobId, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || obj.getClass() != getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DeleteJobAction.Request other = (DeleteJobAction.Request) obj;
|
||||||
|
return Objects.equals(jobId, other.jobId) && Objects.equals(force, other.force);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RequestBuilder extends MasterNodeOperationRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
RequestBuilder(ElasticsearchClient client, DeleteJobAction action) {
|
||||||
|
super(client, action, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends AcknowledgedResponse {
|
||||||
|
|
||||||
|
public Response(boolean acknowledged) {
|
||||||
|
super(acknowledged);
|
||||||
|
}
|
||||||
|
|
||||||
|
Response() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
readAcknowledged(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
writeAcknowledged(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,112 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequest;
|
||||||
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
|
import org.elasticsearch.xpack.ml.job.process.autodetect.state.ModelSnapshotField;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class DeleteModelSnapshotAction extends Action<DeleteModelSnapshotAction.Request,
|
||||||
|
DeleteModelSnapshotAction.Response, DeleteModelSnapshotAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final DeleteModelSnapshotAction INSTANCE = new DeleteModelSnapshotAction();
|
||||||
|
public static final String NAME = "cluster:admin/xpack/ml/job/model_snapshots/delete";
|
||||||
|
|
||||||
|
private DeleteModelSnapshotAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeleteModelSnapshotAction.RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DeleteModelSnapshotAction.Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends ActionRequest {
|
||||||
|
|
||||||
|
private String jobId;
|
||||||
|
private String snapshotId;
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Request(String jobId, String snapshotId) {
|
||||||
|
this.jobId = ExceptionsHelper.requireNonNull(jobId, Job.ID.getPreferredName());
|
||||||
|
this.snapshotId = ExceptionsHelper.requireNonNull(snapshotId, ModelSnapshotField.SNAPSHOT_ID.getPreferredName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJobId() {
|
||||||
|
return jobId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSnapshotId() {
|
||||||
|
return snapshotId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
jobId = in.readString();
|
||||||
|
snapshotId = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeString(jobId);
|
||||||
|
out.writeString(snapshotId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends AcknowledgedResponse {
|
||||||
|
|
||||||
|
public Response(boolean acknowledged) {
|
||||||
|
super(acknowledged);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
readAcknowledged(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
writeAcknowledged(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
public RequestBuilder(ElasticsearchClient client, DeleteModelSnapshotAction action) {
|
||||||
|
super(client, action, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
|
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
||||||
|
import org.elasticsearch.action.support.master.MasterNodeRequest;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class FinalizeJobExecutionAction extends Action<FinalizeJobExecutionAction.Request,
|
||||||
|
FinalizeJobExecutionAction.Response,FinalizeJobExecutionAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final FinalizeJobExecutionAction INSTANCE = new FinalizeJobExecutionAction();
|
||||||
|
public static final String NAME = "cluster:internal/xpack/ml/job/finalize_job_execution";
|
||||||
|
|
||||||
|
private FinalizeJobExecutionAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client, INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends MasterNodeRequest<Request> {
|
||||||
|
|
||||||
|
private String[] jobIds;
|
||||||
|
|
||||||
|
public Request(String[] jobIds) {
|
||||||
|
this.jobIds = jobIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getJobIds() {
|
||||||
|
return jobIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
jobIds = in.readStringArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeStringArray(jobIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RequestBuilder
|
||||||
|
extends MasterNodeOperationRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
public RequestBuilder(ElasticsearchClient client, FinalizeJobExecutionAction action) {
|
||||||
|
super(client, action, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends AcknowledgedResponse {
|
||||||
|
|
||||||
|
Response(boolean acknowledged) {
|
||||||
|
super(acknowledged);
|
||||||
|
}
|
||||||
|
|
||||||
|
Response() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
readAcknowledged(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
writeAcknowledged(out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -7,31 +7,20 @@ package org.elasticsearch.xpack.ml.action;
|
|||||||
|
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.Job;
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.AutodetectProcessManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.output.FlushAcknowledgement;
|
import org.elasticsearch.xpack.ml.job.process.autodetect.output.FlushAcknowledgement;
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.params.FlushJobParams;
|
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.params.TimeRange;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@ -56,7 +45,7 @@ public class FlushJobAction extends Action<FlushJobAction.Request, FlushJobActio
|
|||||||
return new Response();
|
return new Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Request extends TransportJobTaskAction.JobTaskRequest<Request> implements ToXContentObject {
|
public static class Request extends JobTaskRequest<Request> implements ToXContentObject {
|
||||||
|
|
||||||
public static final ParseField CALC_INTERIM = new ParseField("calc_interim");
|
public static final ParseField CALC_INTERIM = new ParseField("calc_interim");
|
||||||
public static final ParseField START = new ParseField("start");
|
public static final ParseField START = new ParseField("start");
|
||||||
@ -279,50 +268,6 @@ public class FlushJobAction extends Action<FlushJobAction.Request, FlushJobActio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends TransportJobTaskAction<Request, Response> {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, TransportService transportService, ThreadPool threadPool, ClusterService clusterService,
|
|
||||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
AutodetectProcessManager processManager) {
|
|
||||||
super(settings, FlushJobAction.NAME, threadPool, clusterService, transportService, actionFilters, indexNameExpressionResolver,
|
|
||||||
FlushJobAction.Request::new, FlushJobAction.Response::new, ThreadPool.Names.SAME, processManager);
|
|
||||||
// ThreadPool.Names.SAME, because operations is executed by autodetect worker thread
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected FlushJobAction.Response readTaskResponse(StreamInput in) throws IOException {
|
|
||||||
Response response = new Response();
|
|
||||||
response.readFrom(in);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void taskOperation(Request request, OpenJobAction.JobTask task, ActionListener<Response> listener) {
|
|
||||||
FlushJobParams.Builder paramsBuilder = FlushJobParams.builder();
|
|
||||||
paramsBuilder.calcInterim(request.getCalcInterim());
|
|
||||||
if (request.getAdvanceTime() != null) {
|
|
||||||
paramsBuilder.advanceTime(request.getAdvanceTime());
|
|
||||||
}
|
|
||||||
if (request.getSkipTime() != null) {
|
|
||||||
paramsBuilder.skipTime(request.getSkipTime());
|
|
||||||
}
|
|
||||||
TimeRange.Builder timeRangeBuilder = TimeRange.builder();
|
|
||||||
if (request.getStart() != null) {
|
|
||||||
timeRangeBuilder.startTime(request.getStart());
|
|
||||||
}
|
|
||||||
if (request.getEnd() != null) {
|
|
||||||
timeRangeBuilder.endTime(request.getEnd());
|
|
||||||
}
|
|
||||||
paramsBuilder.forTimeRange(timeRangeBuilder.build());
|
|
||||||
processManager.flushJob(task, paramsBuilder.build(), ActionListener.wrap(
|
|
||||||
flushAcknowledgement -> {
|
|
||||||
listener.onResponse(new Response(true,
|
|
||||||
flushAcknowledgement == null ? null : flushAcknowledgement.getLastFinalizedBucketEnd()));
|
|
||||||
}, listener::onFailure
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5,42 +5,27 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.Version;
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.job.JobManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.Job;
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.AutodetectProcessManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.params.ForecastParams;
|
|
||||||
import org.elasticsearch.xpack.ml.job.results.Forecast;
|
import org.elasticsearch.xpack.ml.job.results.Forecast;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static org.elasticsearch.xpack.ml.action.ForecastJobAction.Request.DURATION;
|
public class ForecastJobAction extends Action<ForecastJobAction.Request, ForecastJobAction.Response,
|
||||||
|
ForecastJobAction.RequestBuilder> {
|
||||||
public class ForecastJobAction extends Action<ForecastJobAction.Request, ForecastJobAction.Response, ForecastJobAction.RequestBuilder> {
|
|
||||||
|
|
||||||
public static final ForecastJobAction INSTANCE = new ForecastJobAction();
|
public static final ForecastJobAction INSTANCE = new ForecastJobAction();
|
||||||
public static final String NAME = "cluster:admin/xpack/ml/job/forecast";
|
public static final String NAME = "cluster:admin/xpack/ml/job/forecast";
|
||||||
@ -59,7 +44,7 @@ public class ForecastJobAction extends Action<ForecastJobAction.Request, Forecas
|
|||||||
return new Response();
|
return new Response();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Request extends TransportJobTaskAction.JobTaskRequest<Request> implements ToXContentObject {
|
public static class Request extends JobTaskRequest<Request> implements ToXContentObject {
|
||||||
|
|
||||||
public static final ParseField DURATION = new ParseField("duration");
|
public static final ParseField DURATION = new ParseField("duration");
|
||||||
public static final ParseField EXPIRES_IN = new ParseField("expires_in");
|
public static final ParseField EXPIRES_IN = new ParseField("expires_in");
|
||||||
@ -108,8 +93,8 @@ public class ForecastJobAction extends Action<ForecastJobAction.Request, Forecas
|
|||||||
+ duration.getStringRep() + "]");
|
+ duration.getStringRep() + "]");
|
||||||
}
|
}
|
||||||
if (this.duration.compareTo(MAX_DURATION) > 0) {
|
if (this.duration.compareTo(MAX_DURATION) > 0) {
|
||||||
throw new IllegalArgumentException("[" + DURATION.getPreferredName() + "] must be " + MAX_DURATION.getStringRep()
|
throw new IllegalArgumentException("[" + DURATION.getPreferredName() + "] must be "
|
||||||
+ " or less: [" + duration.getStringRep() + "]");
|
+ MAX_DURATION.getStringRep() + " or less: [" + duration.getStringRep() + "]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,69 +232,5 @@ public class ForecastJobAction extends Action<ForecastJobAction.Request, Forecas
|
|||||||
return Objects.hash(acknowledged, forecastId);
|
return Objects.hash(acknowledged, forecastId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends TransportJobTaskAction<Request, Response> {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, TransportService transportService, ThreadPool threadPool, ClusterService clusterService,
|
|
||||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
AutodetectProcessManager processManager) {
|
|
||||||
super(settings, ForecastJobAction.NAME, threadPool, clusterService, transportService, actionFilters,
|
|
||||||
indexNameExpressionResolver, ForecastJobAction.Request::new, ForecastJobAction.Response::new, ThreadPool.Names.SAME,
|
|
||||||
processManager);
|
|
||||||
// ThreadPool.Names.SAME, because operations is executed by autodetect worker thread
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ForecastJobAction.Response readTaskResponse(StreamInput in) throws IOException {
|
|
||||||
Response response = new Response();
|
|
||||||
response.readFrom(in);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void taskOperation(Request request, OpenJobAction.JobTask task, ActionListener<Response> listener) {
|
|
||||||
ClusterState state = clusterService.state();
|
|
||||||
Job job = JobManager.getJobOrThrowIfUnknown(task.getJobId(), state);
|
|
||||||
validate(job, request);
|
|
||||||
|
|
||||||
ForecastParams.Builder paramsBuilder = ForecastParams.builder();
|
|
||||||
|
|
||||||
if (request.getDuration() != null) {
|
|
||||||
paramsBuilder.duration(request.getDuration());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.getExpiresIn() != null) {
|
|
||||||
paramsBuilder.expiresIn(request.getExpiresIn());
|
|
||||||
}
|
|
||||||
|
|
||||||
ForecastParams params = paramsBuilder.build();
|
|
||||||
processManager.forecastJob(task, params, e -> {
|
|
||||||
if (e == null) {
|
|
||||||
listener.onResponse(new Response(true, params.getForecastId()));
|
|
||||||
} else {
|
|
||||||
listener.onFailure(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static void validate(Job job, Request request) {
|
|
||||||
if (job.getJobVersion() == null || job.getJobVersion().before(Version.V_6_1_0)) {
|
|
||||||
throw ExceptionsHelper.badRequestException(
|
|
||||||
"Cannot run forecast because jobs created prior to version 6.1 are not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request.getDuration() != null) {
|
|
||||||
TimeValue duration = request.getDuration();
|
|
||||||
TimeValue bucketSpan = job.getAnalysisConfig().getBucketSpan();
|
|
||||||
|
|
||||||
if (duration.compareTo(bucketSpan) < 0) {
|
|
||||||
throw ExceptionsHelper.badRequestException(
|
|
||||||
"[" + DURATION.getPreferredName() + "] must be greater or equal to the bucket span: [" + duration.getStringRep()
|
|
||||||
+ "/" + bucketSpan.getStringRep() + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -7,34 +7,22 @@ package org.elasticsearch.xpack.ml.action;
|
|||||||
|
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequest;
|
import org.elasticsearch.action.ActionRequest;
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.HandledTransportAction;
|
|
||||||
import org.elasticsearch.client.Client;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
||||||
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
||||||
import org.elasticsearch.xpack.ml.job.JobManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.Job;
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.BucketsQueryBuilder;
|
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobProvider;
|
|
||||||
import org.elasticsearch.xpack.ml.job.results.Bucket;
|
import org.elasticsearch.xpack.ml.job.results.Bucket;
|
||||||
import org.elasticsearch.xpack.ml.job.results.Result;
|
import org.elasticsearch.xpack.ml.job.results.Result;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
@ -371,47 +359,4 @@ public class GetBucketsAction extends Action<GetBucketsAction.Request, GetBucket
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends HandledTransportAction<Request, Response> {
|
|
||||||
|
|
||||||
private final JobProvider jobProvider;
|
|
||||||
private final JobManager jobManager;
|
|
||||||
private final Client client;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, ThreadPool threadPool, TransportService transportService,
|
|
||||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
JobProvider jobProvider, JobManager jobManager, Client client) {
|
|
||||||
super(settings, NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver, Request::new);
|
|
||||||
this.jobProvider = jobProvider;
|
|
||||||
this.jobManager = jobManager;
|
|
||||||
this.client = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Request request, ActionListener<Response> listener) {
|
|
||||||
jobManager.getJobOrThrowIfUnknown(request.getJobId());
|
|
||||||
|
|
||||||
BucketsQueryBuilder query =
|
|
||||||
new BucketsQueryBuilder().expand(request.expand)
|
|
||||||
.includeInterim(request.excludeInterim == false)
|
|
||||||
.start(request.start)
|
|
||||||
.end(request.end)
|
|
||||||
.anomalyScoreThreshold(request.anomalyScore)
|
|
||||||
.sortField(request.sort)
|
|
||||||
.sortDescending(request.descending);
|
|
||||||
|
|
||||||
if (request.pageParams != null) {
|
|
||||||
query.from(request.pageParams.getFrom())
|
|
||||||
.size(request.pageParams.getSize());
|
|
||||||
}
|
|
||||||
if (request.timestamp != null) {
|
|
||||||
query.timestamp(request.timestamp);
|
|
||||||
} else {
|
|
||||||
query.start(request.start);
|
|
||||||
query.end(request.end);
|
|
||||||
}
|
|
||||||
jobProvider.buckets(request.jobId, query, q -> listener.onResponse(new Response(q)), listener::onFailure, client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -258,62 +258,4 @@ public class GetCalendarEventsAction extends Action<GetCalendarEventsAction.Requ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends HandledTransportAction<Request, Response> {
|
|
||||||
|
|
||||||
private final JobProvider jobProvider;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, ThreadPool threadPool,
|
|
||||||
TransportService transportService, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
JobProvider jobProvider) {
|
|
||||||
super(settings, NAME, threadPool, transportService, actionFilters,
|
|
||||||
indexNameExpressionResolver, Request::new);
|
|
||||||
this.jobProvider = jobProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Request request, ActionListener<Response> listener) {
|
|
||||||
ActionListener<Boolean> calendarExistsListener = ActionListener.wrap(
|
|
||||||
r -> {
|
|
||||||
SpecialEventsQueryBuilder query = new SpecialEventsQueryBuilder()
|
|
||||||
.after(request.getAfter())
|
|
||||||
.before(request.getBefore())
|
|
||||||
.from(request.getPageParams().getFrom())
|
|
||||||
.size(request.getPageParams().getSize());
|
|
||||||
|
|
||||||
if (GetCalendarsAction.Request.ALL.equals(request.getCalendarId()) == false) {
|
|
||||||
query.calendarIds(Collections.singletonList(request.getCalendarId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
ActionListener<QueryPage<SpecialEvent>> eventsListener = ActionListener.wrap(
|
|
||||||
events -> {
|
|
||||||
listener.onResponse(new Response(events));
|
|
||||||
},
|
|
||||||
listener::onFailure
|
|
||||||
);
|
|
||||||
|
|
||||||
if (request.getJobId() != null) {
|
|
||||||
jobProvider.specialEventsForJob(request.getJobId(), query, eventsListener);
|
|
||||||
} else {
|
|
||||||
jobProvider.specialEvents(query, eventsListener);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
listener::onFailure);
|
|
||||||
|
|
||||||
checkCalendarExists(request.getCalendarId(), calendarExistsListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkCalendarExists(String calendarId, ActionListener<Boolean> listener) {
|
|
||||||
if (GetCalendarsAction.Request.ALL.equals(calendarId)) {
|
|
||||||
listener.onResponse(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
jobProvider.calendar(calendarId, ActionListener.wrap(
|
|
||||||
c -> listener.onResponse(true),
|
|
||||||
listener::onFailure
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -6,36 +6,25 @@
|
|||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequest;
|
import org.elasticsearch.action.ActionRequest;
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.HandledTransportAction;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.StatusToXContentObject;
|
import org.elasticsearch.common.xcontent.StatusToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.rest.RestStatus;
|
import org.elasticsearch.rest.RestStatus;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
||||||
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
||||||
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.CalendarQueryBuilder;
|
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobProvider;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||||
@ -227,54 +216,4 @@ public class GetCalendarsAction extends Action<GetCalendarsAction.Request, GetCa
|
|||||||
return Strings.toString(this);
|
return Strings.toString(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends HandledTransportAction<Request, Response> {
|
|
||||||
|
|
||||||
private final JobProvider jobProvider;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, ThreadPool threadPool,
|
|
||||||
TransportService transportService, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
JobProvider jobProvider) {
|
|
||||||
super(settings, NAME, threadPool, transportService, actionFilters,
|
|
||||||
indexNameExpressionResolver, Request::new);
|
|
||||||
this.jobProvider = jobProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Request request, ActionListener<Response> listener) {
|
|
||||||
final String calendarId = request.getCalendarId();
|
|
||||||
if (request.getCalendarId() != null && Request.ALL.equals(request.getCalendarId()) == false) {
|
|
||||||
getCalendar(calendarId, listener);
|
|
||||||
} else {
|
|
||||||
PageParams pageParams = request.getPageParams();
|
|
||||||
if (pageParams == null) {
|
|
||||||
pageParams = PageParams.defaultParams();
|
|
||||||
}
|
|
||||||
getCalendars(pageParams, listener);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void getCalendar(String calendarId, ActionListener<Response> listener) {
|
|
||||||
|
|
||||||
jobProvider.calendar(calendarId, ActionListener.wrap(
|
|
||||||
calendar -> {
|
|
||||||
QueryPage<Calendar> page = new QueryPage<>(Collections.singletonList(calendar), 1, Calendar.RESULTS_FIELD);
|
|
||||||
listener.onResponse(new Response(page));
|
|
||||||
},
|
|
||||||
listener::onFailure
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void getCalendars(PageParams pageParams, ActionListener<Response> listener) {
|
|
||||||
CalendarQueryBuilder query = new CalendarQueryBuilder().pageParams(pageParams).sort(true);
|
|
||||||
jobProvider.calendars(query, ActionListener.wrap(
|
|
||||||
calendars -> {
|
|
||||||
listener.onResponse(new Response(calendars));
|
|
||||||
},
|
|
||||||
listener::onFailure
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -6,32 +6,21 @@
|
|||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequest;
|
import org.elasticsearch.action.ActionRequest;
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.HandledTransportAction;
|
|
||||||
import org.elasticsearch.client.Client;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
||||||
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
||||||
import org.elasticsearch.xpack.ml.job.JobManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.Job;
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobProvider;
|
|
||||||
import org.elasticsearch.xpack.ml.job.results.CategoryDefinition;
|
import org.elasticsearch.xpack.ml.job.results.CategoryDefinition;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
@ -93,6 +82,12 @@ Action<GetCategoriesAction.Request, GetCategoriesAction.Response, GetCategoriesA
|
|||||||
Request() {
|
Request() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getJobId() { return jobId; }
|
||||||
|
|
||||||
|
public PageParams getPageParams() { return pageParams; }
|
||||||
|
|
||||||
|
public Long getCategoryId() { return categoryId; }
|
||||||
|
|
||||||
public void setCategoryId(Long categoryId) {
|
public void setCategoryId(Long categoryId) {
|
||||||
if (pageParams != null) {
|
if (pageParams != null) {
|
||||||
throw new IllegalArgumentException("Param [" + CATEGORY_ID.getPreferredName() + "] is incompatible with ["
|
throw new IllegalArgumentException("Param [" + CATEGORY_ID.getPreferredName() + "] is incompatible with ["
|
||||||
@ -226,29 +221,4 @@ Action<GetCategoriesAction.Request, GetCategoriesAction.Response, GetCategoriesA
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends HandledTransportAction<Request, Response> {
|
|
||||||
|
|
||||||
private final JobProvider jobProvider;
|
|
||||||
private final Client client;
|
|
||||||
private final JobManager jobManager;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, ThreadPool threadPool, TransportService transportService, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver, JobProvider jobProvider, Client client, JobManager jobManager) {
|
|
||||||
super(settings, NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver, Request::new);
|
|
||||||
this.jobProvider = jobProvider;
|
|
||||||
this.client = client;
|
|
||||||
this.jobManager = jobManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Request request, ActionListener<Response> listener) {
|
|
||||||
jobManager.getJobOrThrowIfUnknown(request.jobId);
|
|
||||||
|
|
||||||
Integer from = request.pageParams != null ? request.pageParams.getFrom() : null;
|
|
||||||
Integer size = request.pageParams != null ? request.pageParams.getSize() : null;
|
|
||||||
jobProvider.categoryDefinitions(request.jobId, request.categoryId, from, size,
|
|
||||||
r -> listener.onResponse(new Response(r)), listener::onFailure, client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -7,39 +7,23 @@ package org.elasticsearch.xpack.ml.action;
|
|||||||
|
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.master.MasterNodeReadOperationRequestBuilder;
|
import org.elasticsearch.action.support.master.MasterNodeReadOperationRequestBuilder;
|
||||||
import org.elasticsearch.action.support.master.MasterNodeReadRequest;
|
import org.elasticsearch.action.support.master.MasterNodeReadRequest;
|
||||||
import org.elasticsearch.action.support.master.TransportMasterNodeReadAction;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
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.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.MlMetadata;
|
|
||||||
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
||||||
import org.elasticsearch.xpack.ml.datafeed.DatafeedConfig;
|
import org.elasticsearch.xpack.ml.datafeed.DatafeedConfig;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class GetDatafeedsAction extends Action<GetDatafeedsAction.Request, GetDatafeedsAction.Response,
|
public class GetDatafeedsAction extends Action<GetDatafeedsAction.Request, GetDatafeedsAction.Response,
|
||||||
GetDatafeedsAction.RequestBuilder> {
|
GetDatafeedsAction.RequestBuilder> {
|
||||||
@ -200,45 +184,4 @@ public class GetDatafeedsAction extends Action<GetDatafeedsAction.Request, GetDa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends TransportMasterNodeReadAction<Request, Response> {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, TransportService transportService, ClusterService clusterService,
|
|
||||||
ThreadPool threadPool, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver) {
|
|
||||||
super(settings, GetDatafeedsAction.NAME, transportService, clusterService, threadPool, actionFilters,
|
|
||||||
Request::new, indexNameExpressionResolver);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String executor() {
|
|
||||||
return ThreadPool.Names.SAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Response newResponse() {
|
|
||||||
return new Response();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void masterOperation(Request request, ClusterState state, ActionListener<Response> listener) throws Exception {
|
|
||||||
logger.debug("Get datafeed '{}'", request.getDatafeedId());
|
|
||||||
|
|
||||||
MlMetadata mlMetadata = state.metaData().custom(MlMetadata.TYPE);
|
|
||||||
if (mlMetadata == null) {
|
|
||||||
mlMetadata = MlMetadata.EMPTY_METADATA;
|
|
||||||
}
|
|
||||||
Set<String> expandedDatafeedIds = mlMetadata.expandDatafeedIds(request.getDatafeedId(), request.allowNoDatafeeds());
|
|
||||||
List<DatafeedConfig> datafeedConfigs = new ArrayList<>();
|
|
||||||
for (String expandedDatafeedId : expandedDatafeedIds) {
|
|
||||||
datafeedConfigs.add(mlMetadata.getDatafeed(expandedDatafeedId));
|
|
||||||
}
|
|
||||||
|
|
||||||
listener.onResponse(new Response(new QueryPage<>(datafeedConfigs, datafeedConfigs.size(), DatafeedConfig.RESULTS_FIELD)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ClusterBlockException checkBlock(Request request, ClusterState state) {
|
|
||||||
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -7,47 +7,28 @@ package org.elasticsearch.xpack.ml.action;
|
|||||||
|
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.master.MasterNodeReadOperationRequestBuilder;
|
import org.elasticsearch.action.support.master.MasterNodeReadOperationRequestBuilder;
|
||||||
import org.elasticsearch.action.support.master.MasterNodeReadRequest;
|
import org.elasticsearch.action.support.master.MasterNodeReadRequest;
|
||||||
import org.elasticsearch.action.support.master.TransportMasterNodeReadAction;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
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.node.DiscoveryNode;
|
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.MlMetadata;
|
|
||||||
import org.elasticsearch.xpack.ml.action.GetDatafeedsStatsAction.Response.DatafeedStats;
|
|
||||||
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
||||||
import org.elasticsearch.xpack.ml.datafeed.DatafeedConfig;
|
import org.elasticsearch.xpack.ml.datafeed.DatafeedConfig;
|
||||||
import org.elasticsearch.xpack.ml.datafeed.DatafeedState;
|
import org.elasticsearch.xpack.ml.datafeed.DatafeedState;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
import org.elasticsearch.xpack.persistent.PersistentTasksCustomMetaData;
|
|
||||||
import org.elasticsearch.xpack.persistent.PersistentTasksCustomMetaData.PersistentTask;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class GetDatafeedsStatsAction extends Action<GetDatafeedsStatsAction.Request, GetDatafeedsStatsAction.Response,
|
public class GetDatafeedsStatsAction extends Action<GetDatafeedsStatsAction.Request, GetDatafeedsStatsAction.Response,
|
||||||
GetDatafeedsStatsAction.RequestBuilder> {
|
GetDatafeedsStatsAction.RequestBuilder> {
|
||||||
@ -301,63 +282,4 @@ public class GetDatafeedsStatsAction extends Action<GetDatafeedsStatsAction.Requ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends TransportMasterNodeReadAction<Request, Response> {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, TransportService transportService, ClusterService clusterService,
|
|
||||||
ThreadPool threadPool, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver) {
|
|
||||||
super(settings, GetDatafeedsStatsAction.NAME, transportService, clusterService, threadPool, actionFilters,
|
|
||||||
Request::new, indexNameExpressionResolver);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String executor() {
|
|
||||||
return ThreadPool.Names.SAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Response newResponse() {
|
|
||||||
return new Response();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void masterOperation(Request request, ClusterState state,
|
|
||||||
ActionListener<Response> listener) throws Exception {
|
|
||||||
logger.debug("Get stats for datafeed '{}'", request.getDatafeedId());
|
|
||||||
|
|
||||||
MlMetadata mlMetadata = state.metaData().custom(MlMetadata.TYPE);
|
|
||||||
if (mlMetadata == null) {
|
|
||||||
mlMetadata = MlMetadata.EMPTY_METADATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> expandedDatafeedIds = mlMetadata.expandDatafeedIds(request.getDatafeedId(), request.allowNoDatafeeds());
|
|
||||||
|
|
||||||
PersistentTasksCustomMetaData tasksInProgress = state.getMetaData().custom(PersistentTasksCustomMetaData.TYPE);
|
|
||||||
List<DatafeedStats> results = expandedDatafeedIds.stream()
|
|
||||||
.map(datafeedId -> getDatafeedStats(datafeedId, state, tasksInProgress))
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
QueryPage<DatafeedStats> statsPage = new QueryPage<>(results, results.size(),
|
|
||||||
DatafeedConfig.RESULTS_FIELD);
|
|
||||||
listener.onResponse(new Response(statsPage));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static DatafeedStats getDatafeedStats(String datafeedId, ClusterState state,
|
|
||||||
PersistentTasksCustomMetaData tasks) {
|
|
||||||
PersistentTask<?> task = MlMetadata.getDatafeedTask(datafeedId, tasks);
|
|
||||||
DatafeedState datafeedState = MlMetadata.getDatafeedState(datafeedId, tasks);
|
|
||||||
DiscoveryNode node = null;
|
|
||||||
String explanation = null;
|
|
||||||
if (task != null) {
|
|
||||||
node = state.nodes().get(task.getExecutorNode());
|
|
||||||
explanation = task.getAssignment().getExplanation();
|
|
||||||
}
|
|
||||||
return new DatafeedStats(datafeedId, datafeedState, node, explanation);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ClusterBlockException checkBlock(Request request, ClusterState state) {
|
|
||||||
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,185 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequest;
|
||||||
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.ActionResponse;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
import org.elasticsearch.common.Strings;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.common.xcontent.StatusToXContentObject;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.rest.RestStatus;
|
||||||
|
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
||||||
|
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
||||||
|
import org.elasticsearch.xpack.ml.job.config.MlFilter;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||||
|
|
||||||
|
|
||||||
|
public class GetFiltersAction extends Action<GetFiltersAction.Request, GetFiltersAction.Response, GetFiltersAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final GetFiltersAction INSTANCE = new GetFiltersAction();
|
||||||
|
public static final String NAME = "cluster:admin/xpack/ml/filters/get";
|
||||||
|
|
||||||
|
private GetFiltersAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends ActionRequest {
|
||||||
|
|
||||||
|
private String filterId;
|
||||||
|
private PageParams pageParams;
|
||||||
|
|
||||||
|
public Request() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFilterId(String filterId) {
|
||||||
|
this.filterId = filterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFilterId() {
|
||||||
|
return filterId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PageParams getPageParams() {
|
||||||
|
return pageParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPageParams(PageParams pageParams) {
|
||||||
|
this.pageParams = pageParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
ActionRequestValidationException validationException = null;
|
||||||
|
if (pageParams != null && filterId != null) {
|
||||||
|
validationException = addValidationError("Params [" + PageParams.FROM.getPreferredName() +
|
||||||
|
", " + PageParams.SIZE.getPreferredName() + "] are incompatible with ["
|
||||||
|
+ MlFilter.ID.getPreferredName() + "]", validationException);
|
||||||
|
}
|
||||||
|
return validationException;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
filterId = in.readOptionalString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeOptionalString(filterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(filterId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Request other = (Request) obj;
|
||||||
|
return Objects.equals(filterId, other.filterId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
public RequestBuilder(ElasticsearchClient client) {
|
||||||
|
super(client, INSTANCE, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends ActionResponse implements StatusToXContentObject {
|
||||||
|
|
||||||
|
private QueryPage<MlFilter> filters;
|
||||||
|
|
||||||
|
public Response(QueryPage<MlFilter> filters) {
|
||||||
|
this.filters = filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
Response() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueryPage<MlFilter> getFilters() {
|
||||||
|
return filters;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
filters = new QueryPage<>(in, MlFilter::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
filters.writeTo(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RestStatus status() {
|
||||||
|
return RestStatus.OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
filters.doXContentBody(builder, params);
|
||||||
|
builder.endObject();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Response other = (Response) obj;
|
||||||
|
return Objects.equals(filters, other.filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
return Strings.toString(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -6,34 +6,22 @@
|
|||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequest;
|
import org.elasticsearch.action.ActionRequest;
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.HandledTransportAction;
|
|
||||||
import org.elasticsearch.client.Client;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
||||||
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
||||||
import org.elasticsearch.xpack.ml.job.JobManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.Job;
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.InfluencersQueryBuilder;
|
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobProvider;
|
|
||||||
import org.elasticsearch.xpack.ml.job.results.Influencer;
|
import org.elasticsearch.xpack.ml.job.results.Influencer;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
@ -301,30 +289,4 @@ extends Action<GetInfluencersAction.Request, GetInfluencersAction.Response, GetI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends HandledTransportAction<Request, Response> {
|
|
||||||
|
|
||||||
private final JobProvider jobProvider;
|
|
||||||
private final Client client;
|
|
||||||
private final JobManager jobManager;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, ThreadPool threadPool, TransportService transportService, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver, JobProvider jobProvider, Client client, JobManager jobManager) {
|
|
||||||
super(settings, NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver, Request::new);
|
|
||||||
this.jobProvider = jobProvider;
|
|
||||||
this.client = client;
|
|
||||||
this.jobManager = jobManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Request request, ActionListener<Response> listener) {
|
|
||||||
jobManager.getJobOrThrowIfUnknown(request.jobId);
|
|
||||||
|
|
||||||
InfluencersQueryBuilder.InfluencersQuery query = new InfluencersQueryBuilder().includeInterim(request.excludeInterim == false)
|
|
||||||
.start(request.start).end(request.end).from(request.pageParams.getFrom()).size(request.pageParams.getSize())
|
|
||||||
.influencerScoreThreshold(request.influencerScore).sortField(request.sort).sortDescending(request.descending).build();
|
|
||||||
jobProvider.influencers(request.jobId, query, page -> listener.onResponse(new Response(page)), listener::onFailure, client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -7,31 +7,18 @@ package org.elasticsearch.xpack.ml.action;
|
|||||||
|
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.master.MasterNodeReadOperationRequestBuilder;
|
import org.elasticsearch.action.support.master.MasterNodeReadOperationRequestBuilder;
|
||||||
import org.elasticsearch.action.support.master.MasterNodeReadRequest;
|
import org.elasticsearch.action.support.master.MasterNodeReadRequest;
|
||||||
import org.elasticsearch.action.support.master.TransportMasterNodeReadAction;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
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.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
||||||
import org.elasticsearch.xpack.ml.job.JobManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.Job;
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
@ -195,39 +182,4 @@ public class GetJobsAction extends Action<GetJobsAction.Request, GetJobsAction.R
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class TransportAction extends TransportMasterNodeReadAction<Request, Response> {
|
|
||||||
|
|
||||||
private final JobManager jobManager;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, TransportService transportService, ClusterService clusterService,
|
|
||||||
ThreadPool threadPool, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
JobManager jobManager) {
|
|
||||||
super(settings, GetJobsAction.NAME, transportService, clusterService, threadPool, actionFilters,
|
|
||||||
Request::new, indexNameExpressionResolver);
|
|
||||||
this.jobManager = jobManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String executor() {
|
|
||||||
return ThreadPool.Names.SAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Response newResponse() {
|
|
||||||
return new Response();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void masterOperation(Request request, ClusterState state, ActionListener<Response> listener) throws Exception {
|
|
||||||
logger.debug("Get job '{}'", request.getJobId());
|
|
||||||
QueryPage<Job> jobs = jobManager.expandJobs(request.getJobId(), request.allowNoJobs(), state);
|
|
||||||
listener.onResponse(new Response(jobs));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ClusterBlockException checkBlock(Request request, ClusterState state) {
|
|
||||||
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_READ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -7,62 +7,37 @@ package org.elasticsearch.xpack.ml.action;
|
|||||||
|
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.FailedNodeException;
|
import org.elasticsearch.action.FailedNodeException;
|
||||||
import org.elasticsearch.action.TaskOperationFailure;
|
import org.elasticsearch.action.TaskOperationFailure;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.tasks.BaseTasksRequest;
|
import org.elasticsearch.action.support.tasks.BaseTasksRequest;
|
||||||
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
||||||
import org.elasticsearch.action.support.tasks.TransportTasksAction;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.cluster.metadata.MetaData;
|
import org.elasticsearch.cluster.metadata.MetaData;
|
||||||
import org.elasticsearch.cluster.node.DiscoveryNode;
|
import org.elasticsearch.cluster.node.DiscoveryNode;
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.collect.Tuple;
|
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.unit.TimeValue;
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
import org.elasticsearch.common.util.concurrent.AtomicArray;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.tasks.Task;
|
import org.elasticsearch.tasks.Task;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.MlMetadata;
|
|
||||||
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
||||||
import org.elasticsearch.xpack.ml.job.config.Job;
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
import org.elasticsearch.xpack.ml.job.config.JobState;
|
import org.elasticsearch.xpack.ml.job.config.JobState;
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobProvider;
|
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.AutodetectProcessManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.state.DataCounts;
|
import org.elasticsearch.xpack.ml.job.process.autodetect.state.DataCounts;
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.state.ModelSizeStats;
|
import org.elasticsearch.xpack.ml.job.process.autodetect.state.ModelSizeStats;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
import org.elasticsearch.xpack.persistent.PersistentTasksCustomMetaData;
|
|
||||||
import org.elasticsearch.xpack.persistent.PersistentTasksCustomMetaData.PersistentTask;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class GetJobsStatsAction extends Action<GetJobsStatsAction.Request, GetJobsStatsAction.Response, GetJobsStatsAction.RequestBuilder> {
|
public class GetJobsStatsAction extends Action<GetJobsStatsAction.Request, GetJobsStatsAction.Response, GetJobsStatsAction.RequestBuilder> {
|
||||||
|
|
||||||
@ -105,6 +80,10 @@ public class GetJobsStatsAction extends Action<GetJobsStatsAction.Request, GetJo
|
|||||||
|
|
||||||
Request() {}
|
Request() {}
|
||||||
|
|
||||||
|
public List<String> getExpandedJobsIds() { return expandedJobsIds; }
|
||||||
|
|
||||||
|
public void setExpandedJobsIds(List<String> expandedJobsIds) { this.expandedJobsIds = expandedJobsIds; }
|
||||||
|
|
||||||
public void setAllowNoJobs(boolean allowNoJobs) {
|
public void setAllowNoJobs(boolean allowNoJobs) {
|
||||||
this.allowNoJobs = allowNoJobs;
|
this.allowNoJobs = allowNoJobs;
|
||||||
}
|
}
|
||||||
@ -119,7 +98,7 @@ public class GetJobsStatsAction extends Action<GetJobsStatsAction.Request, GetJo
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean match(Task task) {
|
public boolean match(Task task) {
|
||||||
return jobId.equals(MetaData.ALL) || OpenJobAction.JobTask.match(task, jobId);
|
return jobId.equals(MetaData.ALL) || OpenJobAction.JobTaskMatcher.match(task, jobId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -375,132 +354,4 @@ public class GetJobsStatsAction extends Action<GetJobsStatsAction.Request, GetJo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends TransportTasksAction<OpenJobAction.JobTask, Request, Response,
|
|
||||||
QueryPage<Response.JobStats>> {
|
|
||||||
|
|
||||||
private final ClusterService clusterService;
|
|
||||||
private final AutodetectProcessManager processManager;
|
|
||||||
private final JobProvider jobProvider;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, TransportService transportService, ThreadPool threadPool, ActionFilters actionFilters,
|
|
||||||
ClusterService clusterService, IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
AutodetectProcessManager processManager, JobProvider jobProvider) {
|
|
||||||
super(settings, GetJobsStatsAction.NAME, threadPool, clusterService, transportService, actionFilters,
|
|
||||||
indexNameExpressionResolver, Request::new, Response::new, ThreadPool.Names.MANAGEMENT);
|
|
||||||
this.clusterService = clusterService;
|
|
||||||
this.processManager = processManager;
|
|
||||||
this.jobProvider = jobProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Task task, Request request, ActionListener<Response> listener) {
|
|
||||||
MlMetadata clusterMlMetadata = clusterService.state().metaData().custom(MlMetadata.TYPE);
|
|
||||||
MlMetadata mlMetadata = (clusterMlMetadata == null) ? MlMetadata.EMPTY_METADATA : clusterMlMetadata;
|
|
||||||
request.expandedJobsIds = new ArrayList<>(mlMetadata.expandJobIds(request.getJobId(), request.allowNoJobs()));
|
|
||||||
ActionListener<Response> finalListener = listener;
|
|
||||||
listener = ActionListener.wrap(response -> gatherStatsForClosedJobs(mlMetadata,
|
|
||||||
request, response, finalListener), listener::onFailure);
|
|
||||||
super.doExecute(task, request, listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Response newResponse(Request request, List<QueryPage<Response.JobStats>> tasks,
|
|
||||||
List<TaskOperationFailure> taskOperationFailures,
|
|
||||||
List<FailedNodeException> failedNodeExceptions) {
|
|
||||||
List<Response.JobStats> stats = new ArrayList<>();
|
|
||||||
for (QueryPage<Response.JobStats> task : tasks) {
|
|
||||||
stats.addAll(task.results());
|
|
||||||
}
|
|
||||||
return new Response(taskOperationFailures, failedNodeExceptions, new QueryPage<>(stats, stats.size(), Job.RESULTS_FIELD));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected QueryPage<Response.JobStats> readTaskResponse(StreamInput in) throws IOException {
|
|
||||||
return new QueryPage<>(in, Response.JobStats::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void taskOperation(Request request, OpenJobAction.JobTask task,
|
|
||||||
ActionListener<QueryPage<Response.JobStats>> listener) {
|
|
||||||
String jobId = task.getJobId();
|
|
||||||
logger.debug("Get stats for job [{}]", jobId);
|
|
||||||
ClusterState state = clusterService.state();
|
|
||||||
PersistentTasksCustomMetaData tasks = state.getMetaData().custom(PersistentTasksCustomMetaData.TYPE);
|
|
||||||
Optional<Tuple<DataCounts, ModelSizeStats>> stats = processManager.getStatistics(task);
|
|
||||||
if (stats.isPresent()) {
|
|
||||||
PersistentTask<?> pTask = MlMetadata.getJobTask(jobId, tasks);
|
|
||||||
DiscoveryNode node = state.nodes().get(pTask.getExecutorNode());
|
|
||||||
JobState jobState = MlMetadata.getJobState(jobId, tasks);
|
|
||||||
String assignmentExplanation = pTask.getAssignment().getExplanation();
|
|
||||||
TimeValue openTime = durationToTimeValue(processManager.jobOpenTime(task));
|
|
||||||
Response.JobStats jobStats = new Response.JobStats(jobId, stats.get().v1(), stats.get().v2(), jobState,
|
|
||||||
node, assignmentExplanation, openTime);
|
|
||||||
listener.onResponse(new QueryPage<>(Collections.singletonList(jobStats), 1, Job.RESULTS_FIELD));
|
|
||||||
} else {
|
|
||||||
listener.onResponse(new QueryPage<>(Collections.emptyList(), 0, Job.RESULTS_FIELD));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Up until now we gathered the stats for jobs that were open,
|
|
||||||
// This method will fetch the stats for missing jobs, that was stored in the jobs index
|
|
||||||
void gatherStatsForClosedJobs(MlMetadata mlMetadata, Request request, Response response,
|
|
||||||
ActionListener<Response> listener) {
|
|
||||||
List<String> jobIds = determineNonDeletedJobIdsWithoutLiveStats(mlMetadata,
|
|
||||||
request.expandedJobsIds, response.jobsStats.results());
|
|
||||||
if (jobIds.isEmpty()) {
|
|
||||||
listener.onResponse(response);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AtomicInteger counter = new AtomicInteger(jobIds.size());
|
|
||||||
AtomicArray<Response.JobStats> jobStats = new AtomicArray<>(jobIds.size());
|
|
||||||
PersistentTasksCustomMetaData tasks = clusterService.state().getMetaData().custom(PersistentTasksCustomMetaData.TYPE);
|
|
||||||
for (int i = 0; i < jobIds.size(); i++) {
|
|
||||||
int slot = i;
|
|
||||||
String jobId = jobIds.get(i);
|
|
||||||
gatherDataCountsAndModelSizeStats(jobId, (dataCounts, modelSizeStats) -> {
|
|
||||||
JobState jobState = MlMetadata.getJobState(jobId, tasks);
|
|
||||||
PersistentTasksCustomMetaData.PersistentTask<?> pTask = MlMetadata.getJobTask(jobId, tasks);
|
|
||||||
String assignmentExplanation = null;
|
|
||||||
if (pTask != null) {
|
|
||||||
assignmentExplanation = pTask.getAssignment().getExplanation();
|
|
||||||
}
|
|
||||||
jobStats.set(slot, new Response.JobStats(jobId, dataCounts, modelSizeStats, jobState, null,
|
|
||||||
assignmentExplanation, null));
|
|
||||||
if (counter.decrementAndGet() == 0) {
|
|
||||||
List<Response.JobStats> results = response.getResponse().results();
|
|
||||||
results.addAll(jobStats.asList());
|
|
||||||
listener.onResponse(new Response(response.getTaskFailures(), response.getNodeFailures(),
|
|
||||||
new QueryPage<>(results, results.size(), Job.RESULTS_FIELD)));
|
|
||||||
}
|
|
||||||
}, listener::onFailure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void gatherDataCountsAndModelSizeStats(String jobId, BiConsumer<DataCounts, ModelSizeStats> handler,
|
|
||||||
Consumer<Exception> errorHandler) {
|
|
||||||
jobProvider.dataCounts(jobId, dataCounts -> {
|
|
||||||
jobProvider.modelSizeStats(jobId, modelSizeStats -> {
|
|
||||||
handler.accept(dataCounts, modelSizeStats);
|
|
||||||
}, errorHandler);
|
|
||||||
}, errorHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
static TimeValue durationToTimeValue(Optional<Duration> duration) {
|
|
||||||
if (duration.isPresent()) {
|
|
||||||
return TimeValue.timeValueSeconds(duration.get().getSeconds());
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static List<String> determineNonDeletedJobIdsWithoutLiveStats(MlMetadata mlMetadata,
|
|
||||||
List<String> requestedJobIds,
|
|
||||||
List<Response.JobStats> stats) {
|
|
||||||
Set<String> excludeJobIds = stats.stream().map(Response.JobStats::getJobId).collect(Collectors.toSet());
|
|
||||||
return requestedJobIds.stream().filter(jobId -> !excludeJobIds.contains(jobId) &&
|
|
||||||
!mlMetadata.isJobDeleted(jobId)).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -6,39 +6,28 @@
|
|||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequest;
|
import org.elasticsearch.action.ActionRequest;
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.HandledTransportAction;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
||||||
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
||||||
import org.elasticsearch.xpack.ml.job.JobManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.Job;
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobProvider;
|
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.state.ModelSnapshot;
|
import org.elasticsearch.xpack.ml.job.process.autodetect.state.ModelSnapshot;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
public class GetModelSnapshotsAction
|
public class GetModelSnapshotsAction
|
||||||
extends Action<GetModelSnapshotsAction.Request, GetModelSnapshotsAction.Response, GetModelSnapshotsAction.RequestBuilder> {
|
extends Action<GetModelSnapshotsAction.Request, GetModelSnapshotsAction.Response, GetModelSnapshotsAction.RequestBuilder> {
|
||||||
@ -298,42 +287,4 @@ extends Action<GetModelSnapshotsAction.Request, GetModelSnapshotsAction.Response
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends HandledTransportAction<Request, Response> {
|
|
||||||
|
|
||||||
private final JobProvider jobProvider;
|
|
||||||
private final JobManager jobManager;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, TransportService transportService, ThreadPool threadPool, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver, JobProvider jobProvider, JobManager jobManager) {
|
|
||||||
super(settings, NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver, Request::new);
|
|
||||||
this.jobProvider = jobProvider;
|
|
||||||
this.jobManager = jobManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Request request, ActionListener<Response> listener) {
|
|
||||||
logger.debug("Get model snapshots for job {} snapshot ID {}. from = {}, size = {}"
|
|
||||||
+ " start = '{}', end='{}', sort={} descending={}",
|
|
||||||
request.getJobId(), request.getSnapshotId(), request.pageParams.getFrom(), request.pageParams.getSize(),
|
|
||||||
request.getStart(), request.getEnd(), request.getSort(), request.getDescOrder());
|
|
||||||
|
|
||||||
jobManager.getJobOrThrowIfUnknown(request.getJobId());
|
|
||||||
|
|
||||||
jobProvider.modelSnapshots(request.getJobId(), request.pageParams.getFrom(), request.pageParams.getSize(),
|
|
||||||
request.getStart(), request.getEnd(), request.getSort(), request.getDescOrder(), request.getSnapshotId(),
|
|
||||||
page -> {
|
|
||||||
listener.onResponse(new Response(clearQuantiles(page)));
|
|
||||||
}, listener::onFailure);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static QueryPage<ModelSnapshot> clearQuantiles(QueryPage<ModelSnapshot> page) {
|
|
||||||
if (page.results() == null) {
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
return new QueryPage<>(page.results().stream().map(snapshot ->
|
|
||||||
new ModelSnapshot.Builder(snapshot).setQuantiles(null).build())
|
|
||||||
.collect(Collectors.toList()), page.count(), page.getResultsField());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,349 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequest;
|
||||||
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.ActionResponse;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
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.joda.DateMathParser;
|
||||||
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.index.mapper.DateFieldMapper;
|
||||||
|
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
||||||
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
|
import org.elasticsearch.xpack.ml.job.messages.Messages;
|
||||||
|
import org.elasticsearch.xpack.ml.job.results.OverallBucket;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.LongSupplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* This action returns summarized bucket results over multiple jobs.
|
||||||
|
* Overall buckets have the span of the largest job's bucket_span.
|
||||||
|
* Their score is calculated by finding the max anomaly score per job
|
||||||
|
* and then averaging the top N.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Overall buckets can be optionally aggregated into larger intervals
|
||||||
|
* by setting the bucket_span parameter. When that is the case, the
|
||||||
|
* overall_score is the max of the overall buckets that are within
|
||||||
|
* the interval.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class GetOverallBucketsAction
|
||||||
|
extends Action<GetOverallBucketsAction.Request, GetOverallBucketsAction.Response, GetOverallBucketsAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final GetOverallBucketsAction INSTANCE = new GetOverallBucketsAction();
|
||||||
|
public static final String NAME = "cluster:monitor/xpack/ml/job/results/overall_buckets/get";
|
||||||
|
|
||||||
|
private GetOverallBucketsAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends ActionRequest implements ToXContentObject {
|
||||||
|
|
||||||
|
public static final ParseField TOP_N = new ParseField("top_n");
|
||||||
|
public static final ParseField BUCKET_SPAN = new ParseField("bucket_span");
|
||||||
|
public static final ParseField OVERALL_SCORE = new ParseField("overall_score");
|
||||||
|
public static final ParseField EXCLUDE_INTERIM = new ParseField("exclude_interim");
|
||||||
|
public static final ParseField START = new ParseField("start");
|
||||||
|
public static final ParseField END = new ParseField("end");
|
||||||
|
public static final ParseField ALLOW_NO_JOBS = new ParseField("allow_no_jobs");
|
||||||
|
|
||||||
|
private static final ObjectParser<Request, Void> PARSER = new ObjectParser<>(NAME, Request::new);
|
||||||
|
|
||||||
|
static {
|
||||||
|
PARSER.declareString((request, jobId) -> request.jobId = jobId, Job.ID);
|
||||||
|
PARSER.declareInt(Request::setTopN, TOP_N);
|
||||||
|
PARSER.declareString(Request::setBucketSpan, BUCKET_SPAN);
|
||||||
|
PARSER.declareDouble(Request::setOverallScore, OVERALL_SCORE);
|
||||||
|
PARSER.declareBoolean(Request::setExcludeInterim, EXCLUDE_INTERIM);
|
||||||
|
PARSER.declareString((request, startTime) -> request.setStart(parseDateOrThrow(
|
||||||
|
startTime, START, System::currentTimeMillis)), START);
|
||||||
|
PARSER.declareString((request, endTime) -> request.setEnd(parseDateOrThrow(
|
||||||
|
endTime, END, System::currentTimeMillis)), END);
|
||||||
|
PARSER.declareBoolean(Request::setAllowNoJobs, ALLOW_NO_JOBS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long parseDateOrThrow(String date, ParseField paramName, LongSupplier now) {
|
||||||
|
DateMathParser dateMathParser = new DateMathParser(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return dateMathParser.parse(date, now);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String msg = Messages.getMessage(Messages.REST_INVALID_DATETIME_PARAMS, paramName.getPreferredName(), date);
|
||||||
|
throw new ElasticsearchParseException(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Request parseRequest(String jobId, XContentParser parser) {
|
||||||
|
Request request = PARSER.apply(parser, null);
|
||||||
|
if (jobId != null) {
|
||||||
|
request.jobId = jobId;
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String jobId;
|
||||||
|
private int topN = 1;
|
||||||
|
private TimeValue bucketSpan;
|
||||||
|
private double overallScore = 0.0;
|
||||||
|
private boolean excludeInterim = false;
|
||||||
|
private Long start;
|
||||||
|
private Long end;
|
||||||
|
private boolean allowNoJobs = true;
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Request(String jobId) {
|
||||||
|
this.jobId = ExceptionsHelper.requireNonNull(jobId, Job.ID.getPreferredName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJobId() {
|
||||||
|
return jobId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTopN() {
|
||||||
|
return topN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTopN(int topN) {
|
||||||
|
if (topN <= 0) {
|
||||||
|
throw new IllegalArgumentException("[topN] parameter must be positive, found [" + topN + "]");
|
||||||
|
}
|
||||||
|
this.topN = topN;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeValue getBucketSpan() {
|
||||||
|
return bucketSpan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBucketSpan(TimeValue bucketSpan) {
|
||||||
|
this.bucketSpan = bucketSpan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBucketSpan(String bucketSpan) {
|
||||||
|
this.bucketSpan = TimeValue.parseTimeValue(bucketSpan, BUCKET_SPAN.getPreferredName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getOverallScore() {
|
||||||
|
return overallScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOverallScore(double overallScore) {
|
||||||
|
this.overallScore = overallScore;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExcludeInterim() {
|
||||||
|
return excludeInterim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExcludeInterim(boolean excludeInterim) {
|
||||||
|
this.excludeInterim = excludeInterim;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getStart() {
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStart(Long start) {
|
||||||
|
this.start = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStart(String start) {
|
||||||
|
setStart(parseDateOrThrow(start, START, System::currentTimeMillis));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getEnd() {
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnd(Long end) {
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEnd(String end) {
|
||||||
|
setEnd(parseDateOrThrow(end, END, System::currentTimeMillis));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean allowNoJobs() {
|
||||||
|
return allowNoJobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowNoJobs(boolean allowNoJobs) {
|
||||||
|
this.allowNoJobs = allowNoJobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
jobId = in.readString();
|
||||||
|
topN = in.readVInt();
|
||||||
|
bucketSpan = in.readOptionalWriteable(TimeValue::new);
|
||||||
|
overallScore = in.readDouble();
|
||||||
|
excludeInterim = in.readBoolean();
|
||||||
|
start = in.readOptionalLong();
|
||||||
|
end = in.readOptionalLong();
|
||||||
|
allowNoJobs = in.readBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeString(jobId);
|
||||||
|
out.writeVInt(topN);
|
||||||
|
out.writeOptionalWriteable(bucketSpan);
|
||||||
|
out.writeDouble(overallScore);
|
||||||
|
out.writeBoolean(excludeInterim);
|
||||||
|
out.writeOptionalLong(start);
|
||||||
|
out.writeOptionalLong(end);
|
||||||
|
out.writeBoolean(allowNoJobs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
builder.field(Job.ID.getPreferredName(), jobId);
|
||||||
|
builder.field(TOP_N.getPreferredName(), topN);
|
||||||
|
if (bucketSpan != null) {
|
||||||
|
builder.field(BUCKET_SPAN.getPreferredName(), bucketSpan.getStringRep());
|
||||||
|
}
|
||||||
|
builder.field(OVERALL_SCORE.getPreferredName(), overallScore);
|
||||||
|
builder.field(EXCLUDE_INTERIM.getPreferredName(), excludeInterim);
|
||||||
|
if (start != null) {
|
||||||
|
builder.field(START.getPreferredName(), String.valueOf(start));
|
||||||
|
}
|
||||||
|
if (end != null) {
|
||||||
|
builder.field(END.getPreferredName(), String.valueOf(end));
|
||||||
|
}
|
||||||
|
builder.field(ALLOW_NO_JOBS.getPreferredName(), allowNoJobs);
|
||||||
|
builder.endObject();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(jobId, topN, bucketSpan, overallScore, excludeInterim, start, end, allowNoJobs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object other) {
|
||||||
|
if (other == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != other.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Request that = (Request) other;
|
||||||
|
return Objects.equals(jobId, that.jobId) &&
|
||||||
|
this.topN == that.topN &&
|
||||||
|
Objects.equals(bucketSpan, that.bucketSpan) &&
|
||||||
|
this.excludeInterim == that.excludeInterim &&
|
||||||
|
this.overallScore == that.overallScore &&
|
||||||
|
Objects.equals(start, that.start) &&
|
||||||
|
Objects.equals(end, that.end) &&
|
||||||
|
this.allowNoJobs == that.allowNoJobs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
RequestBuilder(ElasticsearchClient client) {
|
||||||
|
super(client, INSTANCE, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends ActionResponse implements ToXContentObject {
|
||||||
|
|
||||||
|
private QueryPage<OverallBucket> overallBuckets;
|
||||||
|
|
||||||
|
Response() {
|
||||||
|
overallBuckets = new QueryPage<>(Collections.emptyList(), 0, OverallBucket.RESULTS_FIELD);
|
||||||
|
}
|
||||||
|
|
||||||
|
Response(QueryPage<OverallBucket> overallBuckets) {
|
||||||
|
this.overallBuckets = overallBuckets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueryPage<OverallBucket> getOverallBuckets() {
|
||||||
|
return overallBuckets;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
overallBuckets = new QueryPage<>(in, OverallBucket::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
overallBuckets.writeTo(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
overallBuckets.doXContentBody(builder, params);
|
||||||
|
builder.endObject();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(overallBuckets);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Response other = (Response) obj;
|
||||||
|
return Objects.equals(overallBuckets, other.overallBuckets);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
return Strings.toString(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,35 +6,22 @@
|
|||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequest;
|
import org.elasticsearch.action.ActionRequest;
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.HandledTransportAction;
|
|
||||||
import org.elasticsearch.client.Client;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
import org.elasticsearch.xpack.ml.action.util.PageParams;
|
||||||
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
import org.elasticsearch.xpack.ml.action.util.QueryPage;
|
||||||
import org.elasticsearch.xpack.ml.job.JobManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.Job;
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobProvider;
|
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.RecordsQueryBuilder;
|
|
||||||
import org.elasticsearch.xpack.ml.job.results.AnomalyRecord;
|
import org.elasticsearch.xpack.ml.job.results.AnomalyRecord;
|
||||||
import org.elasticsearch.xpack.ml.job.results.Influencer;
|
import org.elasticsearch.xpack.ml.job.results.Influencer;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
@ -302,38 +289,4 @@ public class GetRecordsAction extends Action<GetRecordsAction.Request, GetRecord
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends HandledTransportAction<Request, Response> {
|
|
||||||
|
|
||||||
private final JobProvider jobProvider;
|
|
||||||
private final JobManager jobManager;
|
|
||||||
private final Client client;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, ThreadPool threadPool, TransportService transportService,
|
|
||||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
JobProvider jobProvider, JobManager jobManager, Client client) {
|
|
||||||
super(settings, NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver, Request::new);
|
|
||||||
this.jobProvider = jobProvider;
|
|
||||||
this.jobManager = jobManager;
|
|
||||||
this.client = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Request request, ActionListener<Response> listener) {
|
|
||||||
|
|
||||||
jobManager.getJobOrThrowIfUnknown(request.getJobId());
|
|
||||||
|
|
||||||
RecordsQueryBuilder query = new RecordsQueryBuilder()
|
|
||||||
.includeInterim(request.excludeInterim == false)
|
|
||||||
.epochStart(request.start)
|
|
||||||
.epochEnd(request.end)
|
|
||||||
.from(request.pageParams.getFrom())
|
|
||||||
.size(request.pageParams.getSize())
|
|
||||||
.recordScore(request.recordScoreFilter)
|
|
||||||
.sortField(request.sort)
|
|
||||||
.sortDescending(request.descending);
|
|
||||||
jobProvider.records(request.jobId, query, page -> listener.onResponse(new Response(page)), listener::onFailure, client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -5,44 +5,25 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.ElasticsearchException;
|
|
||||||
import org.elasticsearch.Version;
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.FailedNodeException;
|
|
||||||
import org.elasticsearch.action.TaskOperationFailure;
|
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.tasks.BaseTasksRequest;
|
import org.elasticsearch.action.support.tasks.BaseTasksRequest;
|
||||||
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
||||||
import org.elasticsearch.action.support.tasks.TransportTasksAction;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.cluster.node.DiscoveryNodes;
|
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent.Params;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.tasks.Task;
|
import org.elasticsearch.tasks.Task;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
import org.elasticsearch.xpack.ml.MLMetadataField;
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.MachineLearning;
|
|
||||||
import org.elasticsearch.xpack.ml.MlMetadata;
|
|
||||||
import org.elasticsearch.xpack.ml.datafeed.DatafeedConfig;
|
import org.elasticsearch.xpack.ml.datafeed.DatafeedConfig;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
import org.elasticsearch.xpack.persistent.PersistentTasksCustomMetaData;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -103,14 +84,14 @@ public class IsolateDatafeedAction
|
|||||||
Request() {
|
Request() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getDatafeedId() {
|
String getDatafeedId() {
|
||||||
return datafeedId;
|
return datafeedId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean match(Task task) {
|
public boolean match(Task task) {
|
||||||
String expectedDescription = MlMetadata.datafeedTaskId(datafeedId);
|
String expectedDescription = MLMetadataField.datafeedTaskId(datafeedId);
|
||||||
if (task instanceof StartDatafeedAction.DatafeedTask && expectedDescription.equals(task.getDescription())){
|
if (task instanceof StartDatafeedAction.DatafeedTaskMatcher && expectedDescription.equals(task.getDescription())){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -197,63 +178,4 @@ public class IsolateDatafeedAction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends TransportTasksAction<StartDatafeedAction.DatafeedTask, Request, Response, Response> {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, TransportService transportService, ThreadPool threadPool,
|
|
||||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
ClusterService clusterService) {
|
|
||||||
super(settings, IsolateDatafeedAction.NAME, threadPool, clusterService, transportService, actionFilters,
|
|
||||||
indexNameExpressionResolver, Request::new, Response::new, MachineLearning.UTILITY_THREAD_POOL_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Task task, Request request, ActionListener<Response> listener) {
|
|
||||||
final ClusterState state = clusterService.state();
|
|
||||||
PersistentTasksCustomMetaData tasks = state.getMetaData().custom(PersistentTasksCustomMetaData.TYPE);
|
|
||||||
PersistentTasksCustomMetaData.PersistentTask<?> datafeedTask = MlMetadata.getDatafeedTask(request.getDatafeedId(), tasks);
|
|
||||||
|
|
||||||
if (datafeedTask == null || datafeedTask.getExecutorNode() == null) {
|
|
||||||
// No running datafeed task to isolate
|
|
||||||
listener.onResponse(new Response());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String executorNode = datafeedTask.getExecutorNode();
|
|
||||||
DiscoveryNodes nodes = state.nodes();
|
|
||||||
if (nodes.resolveNode(executorNode).getVersion().before(Version.V_5_5_0)) {
|
|
||||||
listener.onFailure(new ElasticsearchException("Force delete datafeed is not supported because the datafeed task " +
|
|
||||||
"is running on a node [" + executorNode + "] with a version prior to " + Version.V_5_5_0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
request.setNodes(datafeedTask.getExecutorNode());
|
|
||||||
super.doExecute(task, request, listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Response newResponse(Request request, List<Response> tasks, List<TaskOperationFailure> taskOperationFailures,
|
|
||||||
List<FailedNodeException> failedNodeExceptions) {
|
|
||||||
if (taskOperationFailures.isEmpty() == false) {
|
|
||||||
throw org.elasticsearch.ExceptionsHelper
|
|
||||||
.convertToElastic(taskOperationFailures.get(0).getCause());
|
|
||||||
} else if (failedNodeExceptions.isEmpty() == false) {
|
|
||||||
throw org.elasticsearch.ExceptionsHelper
|
|
||||||
.convertToElastic(failedNodeExceptions.get(0));
|
|
||||||
} else {
|
|
||||||
return new Response();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void taskOperation(Request request, StartDatafeedAction.DatafeedTask datafeedTask, ActionListener<Response> listener) {
|
|
||||||
datafeedTask.isolate();
|
|
||||||
listener.onResponse(new Response());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Response readTaskResponse(StreamInput in) throws IOException {
|
|
||||||
return new Response(in);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.support.tasks.BaseTasksRequest;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.tasks.Task;
|
||||||
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class JobTaskRequest<R extends JobTaskRequest<R>> extends BaseTasksRequest<R> {
|
||||||
|
|
||||||
|
String jobId;
|
||||||
|
|
||||||
|
JobTaskRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
JobTaskRequest(String jobId) {
|
||||||
|
this.jobId = ExceptionsHelper.requireNonNull(jobId, Job.ID.getPreferredName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJobId() {
|
||||||
|
return jobId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
jobId = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeString(jobId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean match(Task task) {
|
||||||
|
return OpenJobAction.JobTaskMatcher.match(task, jobId);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
|
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class KillProcessAction extends Action<KillProcessAction.Request, KillProcessAction.Response,
|
||||||
|
KillProcessAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final KillProcessAction INSTANCE = new KillProcessAction();
|
||||||
|
public static final String NAME = "cluster:internal/xpack/ml/job/kill/process";
|
||||||
|
|
||||||
|
private KillProcessAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
RequestBuilder(ElasticsearchClient client, KillProcessAction action) {
|
||||||
|
super(client, action, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends JobTaskRequest<Request> {
|
||||||
|
|
||||||
|
public Request(String jobId) {
|
||||||
|
super(jobId);
|
||||||
|
}
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends BaseTasksResponse implements Writeable {
|
||||||
|
|
||||||
|
private boolean killed;
|
||||||
|
|
||||||
|
Response() {
|
||||||
|
super(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Response(StreamInput in) throws IOException {
|
||||||
|
super(null, null);
|
||||||
|
readFrom(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
Response(boolean killed) {
|
||||||
|
super(null, null);
|
||||||
|
this.killed = killed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isKilled() {
|
||||||
|
return killed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
killed = in.readBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeBoolean(killed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Response response = (Response) o;
|
||||||
|
return killed == response.killed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(killed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,296 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.Version;
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
|
import org.elasticsearch.action.support.master.MasterNodeRequest;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
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.unit.TimeValue;
|
||||||
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.tasks.Task;
|
||||||
|
import org.elasticsearch.xpack.ml.MachineLearningClientActionPlugin;
|
||||||
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
import org.elasticsearch.xpack.persistent.PersistentTaskParams;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class OpenJobAction extends Action<OpenJobAction.Request, OpenJobAction.Response, OpenJobAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final OpenJobAction INSTANCE = new OpenJobAction();
|
||||||
|
public static final String NAME = "cluster:admin/xpack/ml/job/open";
|
||||||
|
public static final String TASK_NAME = "xpack/ml/job";
|
||||||
|
|
||||||
|
private OpenJobAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends MasterNodeRequest<Request> implements ToXContentObject {
|
||||||
|
|
||||||
|
public static Request fromXContent(XContentParser parser) {
|
||||||
|
return parseRequest(null, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Request parseRequest(String jobId, XContentParser parser) {
|
||||||
|
JobParams jobParams = JobParams.PARSER.apply(parser, null);
|
||||||
|
if (jobId != null) {
|
||||||
|
jobParams.jobId = jobId;
|
||||||
|
}
|
||||||
|
return new Request(jobParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
private JobParams jobParams;
|
||||||
|
|
||||||
|
public Request(JobParams jobParams) {
|
||||||
|
this.jobParams = jobParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Request(String jobId) {
|
||||||
|
this.jobParams = new JobParams(jobId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Request(StreamInput in) throws IOException {
|
||||||
|
readFrom(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public JobParams getJobParams() {
|
||||||
|
return jobParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
jobParams = new JobParams(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
jobParams.writeTo(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
jobParams.toXContent(builder, params);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(jobParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || obj.getClass() != getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
OpenJobAction.Request other = (OpenJobAction.Request) obj;
|
||||||
|
return Objects.equals(jobParams, other.jobParams);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Strings.toString(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class JobParams implements PersistentTaskParams {
|
||||||
|
|
||||||
|
/** TODO Remove in 7.0.0 */
|
||||||
|
public static final ParseField IGNORE_DOWNTIME = new ParseField("ignore_downtime");
|
||||||
|
|
||||||
|
public static final ParseField TIMEOUT = new ParseField("timeout");
|
||||||
|
public static ObjectParser<JobParams, Void> PARSER = new ObjectParser<>(TASK_NAME, JobParams::new);
|
||||||
|
|
||||||
|
static {
|
||||||
|
PARSER.declareString(JobParams::setJobId, Job.ID);
|
||||||
|
PARSER.declareBoolean((p, v) -> {}, IGNORE_DOWNTIME);
|
||||||
|
PARSER.declareString((params, val) ->
|
||||||
|
params.setTimeout(TimeValue.parseTimeValue(val, TIMEOUT.getPreferredName())), TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JobParams fromXContent(XContentParser parser) {
|
||||||
|
return parseRequest(null, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JobParams parseRequest(String jobId, XContentParser parser) {
|
||||||
|
JobParams params = PARSER.apply(parser, null);
|
||||||
|
if (jobId != null) {
|
||||||
|
params.jobId = jobId;
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String jobId;
|
||||||
|
// A big state can take a while to restore. For symmetry with the _close endpoint any
|
||||||
|
// changes here should be reflected there too.
|
||||||
|
private TimeValue timeout = MachineLearningClientActionPlugin.STATE_PERSIST_RESTORE_TIMEOUT;
|
||||||
|
|
||||||
|
JobParams() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public JobParams(String jobId) {
|
||||||
|
this.jobId = ExceptionsHelper.requireNonNull(jobId, Job.ID.getPreferredName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public JobParams(StreamInput in) throws IOException {
|
||||||
|
jobId = in.readString();
|
||||||
|
if (in.getVersion().onOrBefore(Version.V_5_5_0)) {
|
||||||
|
// Read `ignoreDowntime`
|
||||||
|
in.readBoolean();
|
||||||
|
}
|
||||||
|
timeout = TimeValue.timeValueMillis(in.readVLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getJobId() {
|
||||||
|
return jobId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJobId(String jobId) {
|
||||||
|
this.jobId = jobId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeValue getTimeout() {
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeout(TimeValue timeout) {
|
||||||
|
this.timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getWriteableName() {
|
||||||
|
return TASK_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
out.writeString(jobId);
|
||||||
|
if (out.getVersion().onOrBefore(Version.V_5_5_0)) {
|
||||||
|
// Write `ignoreDowntime` - true by default
|
||||||
|
out.writeBoolean(true);
|
||||||
|
}
|
||||||
|
out.writeVLong(timeout.millis());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
builder.field(Job.ID.getPreferredName(), jobId);
|
||||||
|
builder.field(TIMEOUT.getPreferredName(), timeout.getStringRep());
|
||||||
|
builder.endObject();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(jobId, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (obj == null || obj.getClass() != getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
OpenJobAction.JobParams other = (OpenJobAction.JobParams) obj;
|
||||||
|
return Objects.equals(jobId, other.jobId) &&
|
||||||
|
Objects.equals(timeout, other.timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return Strings.toString(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends AcknowledgedResponse {
|
||||||
|
public Response() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response(boolean acknowledged) {
|
||||||
|
super(acknowledged);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
readAcknowledged(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
writeAcknowledged(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
AcknowledgedResponse that = (AcknowledgedResponse) o;
|
||||||
|
return isAcknowledged() == that.isAcknowledged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(isAcknowledged());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface JobTaskMatcher {
|
||||||
|
|
||||||
|
static boolean match(Task task, String expectedJobId) {
|
||||||
|
String expectedDescription = "job-" + expectedJobId;
|
||||||
|
return task instanceof JobTaskMatcher && expectedDescription.equals(task.getDescription());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
RequestBuilder(ElasticsearchClient client, OpenJobAction action) {
|
||||||
|
super(client, action, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -243,68 +243,4 @@ public class PostCalendarEventsAction extends Action<PostCalendarEventsAction.Re
|
|||||||
return Objects.equals(isAcknowledged(), other.isAcknowledged()) && Objects.equals(specialEvent, other.specialEvent);
|
return Objects.equals(isAcknowledged(), other.isAcknowledged()) && Objects.equals(specialEvent, other.specialEvent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends HandledTransportAction<Request, Response> {
|
|
||||||
|
|
||||||
private final Client client;
|
|
||||||
private final JobProvider jobProvider;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, ThreadPool threadPool,
|
|
||||||
TransportService transportService, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
Client client, JobProvider jobProvider) {
|
|
||||||
super(settings, NAME, threadPool, transportService, actionFilters,
|
|
||||||
indexNameExpressionResolver, Request::new);
|
|
||||||
this.client = client;
|
|
||||||
this.jobProvider = jobProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Request request, ActionListener<Response> listener) {
|
|
||||||
List<SpecialEvent> events = request.getSpecialEvents();
|
|
||||||
|
|
||||||
ActionListener<Boolean> calendarExistsListener = ActionListener.wrap(
|
|
||||||
r -> {
|
|
||||||
BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
|
|
||||||
|
|
||||||
for (SpecialEvent event: events) {
|
|
||||||
IndexRequest indexRequest = new IndexRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE);
|
|
||||||
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
|
||||||
indexRequest.source(event.toXContent(builder,
|
|
||||||
new ToXContent.MapParams(Collections.singletonMap(MlMetaIndex.INCLUDE_TYPE_KEY, "true"))));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException("Failed to serialise special event", e);
|
|
||||||
}
|
|
||||||
bulkRequestBuilder.add(indexRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
bulkRequestBuilder.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
|
||||||
|
|
||||||
executeAsyncWithOrigin(client, ML_ORIGIN, BulkAction.INSTANCE, bulkRequestBuilder.request(),
|
|
||||||
new ActionListener<BulkResponse>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(BulkResponse response) {
|
|
||||||
listener.onResponse(new Response(events));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Exception e) {
|
|
||||||
listener.onFailure(
|
|
||||||
ExceptionsHelper.serverError("Error indexing special event", e));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
listener::onFailure);
|
|
||||||
|
|
||||||
checkCalendarExists(request.getCalendarId(), calendarExistsListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkCalendarExists(String calendarId, ActionListener<Boolean> listener) {
|
|
||||||
jobProvider.calendar(calendarId, ActionListener.wrap(
|
|
||||||
c -> listener.onResponse(true),
|
|
||||||
listener::onFailure
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -6,35 +6,23 @@
|
|||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.StatusToXContentObject;
|
import org.elasticsearch.common.xcontent.StatusToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentType;
|
import org.elasticsearch.common.xcontent.XContentType;
|
||||||
import org.elasticsearch.rest.RestStatus;
|
import org.elasticsearch.rest.RestStatus;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.DataDescription;
|
import org.elasticsearch.xpack.ml.job.config.DataDescription;
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.AutodetectProcessManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.params.DataLoadParams;
|
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.params.TimeRange;
|
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.state.DataCounts;
|
import org.elasticsearch.xpack.ml.job.process.autodetect.state.DataCounts;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class PostDataAction extends Action<PostDataAction.Request, PostDataAction.Response, PostDataAction.RequestBuilder> {
|
public class PostDataAction extends Action<PostDataAction.Request, PostDataAction.Response, PostDataAction.RequestBuilder> {
|
||||||
|
|
||||||
@ -71,7 +59,7 @@ public class PostDataAction extends Action<PostDataAction.Request, PostDataActio
|
|||||||
dataCounts = new DataCounts(jobId);
|
dataCounts = new DataCounts(jobId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Response() {
|
Response() {
|
||||||
super(null, null);
|
super(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,7 +117,7 @@ public class PostDataAction extends Action<PostDataAction.Request, PostDataActio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Request extends TransportJobTaskAction.JobTaskRequest<Request> {
|
public static class Request extends JobTaskRequest<Request> {
|
||||||
|
|
||||||
public static final ParseField RESET_START = new ParseField("reset_start");
|
public static final ParseField RESET_START = new ParseField("reset_start");
|
||||||
public static final ParseField RESET_END = new ParseField("reset_end");
|
public static final ParseField RESET_END = new ParseField("reset_end");
|
||||||
@ -234,40 +222,4 @@ public class PostDataAction extends Action<PostDataAction.Request, PostDataActio
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static class TransportAction extends TransportJobTaskAction<Request, Response> {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, TransportService transportService, ThreadPool threadPool, ClusterService clusterService,
|
|
||||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
AutodetectProcessManager processManager) {
|
|
||||||
super(settings, PostDataAction.NAME, threadPool, clusterService, transportService, actionFilters, indexNameExpressionResolver,
|
|
||||||
Request::new, Response::new, ThreadPool.Names.SAME, processManager);
|
|
||||||
// ThreadPool.Names.SAME, because operations is executed by autodetect worker thread
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Response readTaskResponse(StreamInput in) throws IOException {
|
|
||||||
Response response = new Response();
|
|
||||||
response.readFrom(in);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void taskOperation(Request request, OpenJobAction.JobTask task, ActionListener<Response> listener) {
|
|
||||||
TimeRange timeRange = TimeRange.builder().startTime(request.getResetStart()).endTime(request.getResetEnd()).build();
|
|
||||||
DataLoadParams params = new DataLoadParams(timeRange, Optional.ofNullable(request.getDataDescription()));
|
|
||||||
try {
|
|
||||||
processManager.processData(task, request.content.streamInput(), request.getXContentType(), params, (dataCounts, e) -> {
|
|
||||||
if (dataCounts != null) {
|
|
||||||
listener.onResponse(new Response(dataCounts));
|
|
||||||
} else {
|
|
||||||
listener.onFailure(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
listener.onFailure(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,168 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequest;
|
||||||
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.ActionResponse;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
import org.elasticsearch.common.Strings;
|
||||||
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
|
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.common.xcontent.XContentType;
|
||||||
|
import org.elasticsearch.xpack.ml.datafeed.DatafeedConfig;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class PreviewDatafeedAction extends Action<PreviewDatafeedAction.Request, PreviewDatafeedAction.Response,
|
||||||
|
PreviewDatafeedAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final PreviewDatafeedAction INSTANCE = new PreviewDatafeedAction();
|
||||||
|
public static final String NAME = "cluster:admin/xpack/ml/datafeeds/preview";
|
||||||
|
|
||||||
|
private PreviewDatafeedAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends ActionRequest implements ToXContentObject {
|
||||||
|
|
||||||
|
private String datafeedId;
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Request(String datafeedId) {
|
||||||
|
setDatafeedId(datafeedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDatafeedId() {
|
||||||
|
return datafeedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final void setDatafeedId(String datafeedId) {
|
||||||
|
this.datafeedId = ExceptionsHelper.requireNonNull(datafeedId, DatafeedConfig.ID.getPreferredName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
datafeedId = in.readString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeString(datafeedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
builder.field(DatafeedConfig.ID.getPreferredName(), datafeedId);
|
||||||
|
builder.endObject();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(datafeedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Request other = (Request) obj;
|
||||||
|
return Objects.equals(datafeedId, other.datafeedId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
RequestBuilder(ElasticsearchClient client) {
|
||||||
|
super(client, INSTANCE, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends ActionResponse implements ToXContentObject {
|
||||||
|
|
||||||
|
private BytesReference preview;
|
||||||
|
|
||||||
|
Response() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Response(BytesReference preview) {
|
||||||
|
this.preview = preview;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
preview = in.readBytesReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeBytesReference(preview);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.rawValue(preview, XContentType.JSON);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(preview);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Response other = (Response) obj;
|
||||||
|
return Objects.equals(preview, other.preview);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final String toString() {
|
||||||
|
return Strings.toString(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,52 +6,28 @@
|
|||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequest;
|
import org.elasticsearch.action.ActionRequest;
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.DocWriteRequest;
|
|
||||||
import org.elasticsearch.action.index.IndexAction;
|
|
||||||
import org.elasticsearch.action.index.IndexRequest;
|
|
||||||
import org.elasticsearch.action.index.IndexResponse;
|
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.HandledTransportAction;
|
|
||||||
import org.elasticsearch.action.support.WriteRequest;
|
|
||||||
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
import org.elasticsearch.client.Client;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.ClusterState;
|
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.MlMetaIndex;
|
|
||||||
import org.elasticsearch.xpack.ml.MlMetadata;
|
|
||||||
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
||||||
import org.elasticsearch.xpack.ml.job.messages.Messages;
|
import org.elasticsearch.xpack.ml.job.messages.Messages;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
import org.elasticsearch.xpack.watcher.support.Exceptions;
|
import org.elasticsearch.xpack.watcher.support.Exceptions;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
import static org.elasticsearch.action.ValidateActions.addValidationError;
|
||||||
import static org.elasticsearch.xpack.ClientHelper.ML_ORIGIN;
|
|
||||||
import static org.elasticsearch.xpack.ClientHelper.executeAsyncWithOrigin;
|
|
||||||
|
|
||||||
public class PutCalendarAction extends Action<PutCalendarAction.Request, PutCalendarAction.Response, PutCalendarAction.RequestBuilder> {
|
public class PutCalendarAction extends Action<PutCalendarAction.Request, PutCalendarAction.Response, PutCalendarAction.RequestBuilder> {
|
||||||
public static final PutCalendarAction INSTANCE = new PutCalendarAction();
|
public static final PutCalendarAction INSTANCE = new PutCalendarAction();
|
||||||
@ -202,66 +178,4 @@ public class PutCalendarAction extends Action<PutCalendarAction.Request, PutCale
|
|||||||
return Objects.equals(isAcknowledged(), other.isAcknowledged()) && Objects.equals(calendar, other.calendar);
|
return Objects.equals(isAcknowledged(), other.isAcknowledged()) && Objects.equals(calendar, other.calendar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends HandledTransportAction<Request, Response> {
|
|
||||||
|
|
||||||
private final Client client;
|
|
||||||
private final ClusterService clusterService;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, ThreadPool threadPool,
|
|
||||||
TransportService transportService, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
Client client, ClusterService clusterService) {
|
|
||||||
super(settings, NAME, threadPool, transportService, actionFilters,
|
|
||||||
indexNameExpressionResolver, Request::new);
|
|
||||||
this.client = client;
|
|
||||||
this.clusterService = clusterService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Request request, ActionListener<Response> listener) {
|
|
||||||
Calendar calendar = request.getCalendar();
|
|
||||||
|
|
||||||
checkJobsExist(calendar.getJobIds(), listener::onFailure);
|
|
||||||
|
|
||||||
IndexRequest indexRequest = new IndexRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE, calendar.documentId());
|
|
||||||
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
|
||||||
indexRequest.source(calendar.toXContent(builder,
|
|
||||||
new ToXContent.MapParams(Collections.singletonMap(MlMetaIndex.INCLUDE_TYPE_KEY, "true"))));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException("Failed to serialise calendar with id [" + calendar.getId() + "]", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make it an error to overwrite an existing calendar
|
|
||||||
indexRequest.opType(DocWriteRequest.OpType.CREATE);
|
|
||||||
indexRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
|
||||||
|
|
||||||
executeAsyncWithOrigin(client, ML_ORIGIN, IndexAction.INSTANCE, indexRequest,
|
|
||||||
new ActionListener<IndexResponse>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(IndexResponse indexResponse) {
|
|
||||||
listener.onResponse(new Response(calendar));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Exception e) {
|
|
||||||
listener.onFailure(
|
|
||||||
ExceptionsHelper.serverError("Error putting calendar with id [" + calendar.getId() + "]", e));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkJobsExist(List<String> jobIds, Consumer<Exception> errorHandler) {
|
|
||||||
ClusterState state = clusterService.state();
|
|
||||||
MlMetadata mlMetadata = state.getMetaData().custom(MlMetadata.TYPE);
|
|
||||||
for (String jobId: jobIds) {
|
|
||||||
Set<String> jobs = mlMetadata.expandJobIds(jobId, true);
|
|
||||||
if (jobs.isEmpty()) {
|
|
||||||
errorHandler.accept(ExceptionsHelper.missingJobException(jobId));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,160 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
|
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
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.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.xpack.ml.datafeed.DatafeedConfig;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class PutDatafeedAction extends Action<PutDatafeedAction.Request, PutDatafeedAction.Response, PutDatafeedAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final PutDatafeedAction INSTANCE = new PutDatafeedAction();
|
||||||
|
public static final String NAME = "cluster:admin/xpack/ml/datafeeds/put";
|
||||||
|
|
||||||
|
private PutDatafeedAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends AcknowledgedRequest<Request> implements ToXContentObject {
|
||||||
|
|
||||||
|
public static Request parseRequest(String datafeedId, XContentParser parser) {
|
||||||
|
DatafeedConfig.Builder datafeed = DatafeedConfig.CONFIG_PARSER.apply(parser, null);
|
||||||
|
datafeed.setId(datafeedId);
|
||||||
|
return new Request(datafeed.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private DatafeedConfig datafeed;
|
||||||
|
|
||||||
|
public Request(DatafeedConfig datafeed) {
|
||||||
|
this.datafeed = datafeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatafeedConfig getDatafeed() {
|
||||||
|
return datafeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
datafeed = new DatafeedConfig(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
datafeed.writeTo(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
datafeed.toXContent(builder, params);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Request request = (Request) o;
|
||||||
|
return Objects.equals(datafeed, request.datafeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(datafeed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RequestBuilder extends MasterNodeOperationRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
public RequestBuilder(ElasticsearchClient client, PutDatafeedAction action) {
|
||||||
|
super(client, action, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends AcknowledgedResponse implements ToXContentObject {
|
||||||
|
|
||||||
|
private DatafeedConfig datafeed;
|
||||||
|
|
||||||
|
public Response(boolean acked, DatafeedConfig datafeed) {
|
||||||
|
super(acked);
|
||||||
|
this.datafeed = datafeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
Response() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatafeedConfig getResponse() {
|
||||||
|
return datafeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
readAcknowledged(in);
|
||||||
|
datafeed = new DatafeedConfig(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
writeAcknowledged(out);
|
||||||
|
datafeed.writeTo(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
datafeed.doXContentBody(builder, params);
|
||||||
|
builder.endObject();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Response response = (Response) o;
|
||||||
|
return Objects.equals(datafeed, response.datafeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(datafeed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,45 +6,24 @@
|
|||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequest;
|
import org.elasticsearch.action.ActionRequest;
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.bulk.BulkAction;
|
|
||||||
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
|
||||||
import org.elasticsearch.action.bulk.BulkResponse;
|
|
||||||
import org.elasticsearch.action.index.IndexRequest;
|
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.HandledTransportAction;
|
|
||||||
import org.elasticsearch.action.support.WriteRequest;
|
|
||||||
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
import org.elasticsearch.client.Client;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.MlMetaIndex;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.MlFilter;
|
import org.elasticsearch.xpack.ml.job.config.MlFilter;
|
||||||
import org.elasticsearch.xpack.ml.job.messages.Messages;
|
import org.elasticsearch.xpack.ml.job.messages.Messages;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static org.elasticsearch.xpack.ClientHelper.ML_ORIGIN;
|
|
||||||
import static org.elasticsearch.xpack.ClientHelper.executeAsyncWithOrigin;
|
|
||||||
|
|
||||||
|
|
||||||
public class PutFilterAction extends Action<PutFilterAction.Request, PutFilterAction.Response, PutFilterAction.RequestBuilder> {
|
public class PutFilterAction extends Action<PutFilterAction.Request, PutFilterAction.Response, PutFilterAction.RequestBuilder> {
|
||||||
|
|
||||||
@ -161,47 +140,5 @@ public class PutFilterAction extends Action<PutFilterAction.Request, PutFilterAc
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends HandledTransportAction<Request, Response> {
|
|
||||||
|
|
||||||
private final Client client;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, ThreadPool threadPool,
|
|
||||||
TransportService transportService, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
Client client) {
|
|
||||||
super(settings, NAME, threadPool, transportService, actionFilters,
|
|
||||||
indexNameExpressionResolver, Request::new);
|
|
||||||
this.client = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Request request, ActionListener<Response> listener) {
|
|
||||||
MlFilter filter = request.getFilter();
|
|
||||||
IndexRequest indexRequest = new IndexRequest(MlMetaIndex.INDEX_NAME, MlMetaIndex.TYPE, filter.documentId());
|
|
||||||
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
|
||||||
ToXContent.MapParams params = new ToXContent.MapParams(Collections.singletonMap(MlMetaIndex.INCLUDE_TYPE_KEY, "true"));
|
|
||||||
indexRequest.source(filter.toXContent(builder, params));
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException("Failed to serialise filter with id [" + filter.getId() + "]", e);
|
|
||||||
}
|
|
||||||
BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
|
|
||||||
bulkRequestBuilder.add(indexRequest);
|
|
||||||
bulkRequestBuilder.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
|
||||||
|
|
||||||
executeAsyncWithOrigin(client, ML_ORIGIN, BulkAction.INSTANCE, bulkRequestBuilder.request(),
|
|
||||||
new ActionListener<BulkResponse>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(BulkResponse indexResponse) {
|
|
||||||
listener.onResponse(new Response());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Exception e) {
|
|
||||||
listener.onFailure(ExceptionsHelper.serverError("Error putting filter with id [" + filter.getId() + "]", e));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -6,34 +6,17 @@
|
|||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
||||||
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
||||||
import org.elasticsearch.action.support.master.TransportMasterNodeAction;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
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.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.license.LicenseUtils;
|
|
||||||
import org.elasticsearch.license.XPackLicenseState;
|
|
||||||
import org.elasticsearch.tasks.Task;
|
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.XPackPlugin;
|
|
||||||
import org.elasticsearch.xpack.ml.job.JobManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.Job;
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
import org.elasticsearch.xpack.ml.job.messages.Messages;
|
import org.elasticsearch.xpack.ml.job.messages.Messages;
|
||||||
|
|
||||||
@ -200,48 +183,4 @@ public class PutJobAction extends Action<PutJobAction.Request, PutJobAction.Resp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends TransportMasterNodeAction<Request, Response> {
|
|
||||||
|
|
||||||
private final JobManager jobManager;
|
|
||||||
private final XPackLicenseState licenseState;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, TransportService transportService, ClusterService clusterService,
|
|
||||||
ThreadPool threadPool, XPackLicenseState licenseState, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver, JobManager jobManager) {
|
|
||||||
super(settings, PutJobAction.NAME, transportService, clusterService, threadPool, actionFilters,
|
|
||||||
indexNameExpressionResolver, Request::new);
|
|
||||||
this.licenseState = licenseState;
|
|
||||||
this.jobManager = jobManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String executor() {
|
|
||||||
return ThreadPool.Names.SAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Response newResponse() {
|
|
||||||
return new Response();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void masterOperation(Request request, ClusterState state, ActionListener<Response> listener) throws Exception {
|
|
||||||
jobManager.putJob(request, state, listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ClusterBlockException checkBlock(Request request, ClusterState state) {
|
|
||||||
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Task task, Request request, ActionListener<Response> listener) {
|
|
||||||
if (licenseState.isMachineLearningAllowed()) {
|
|
||||||
super.doExecute(task, request, listener);
|
|
||||||
} else {
|
|
||||||
listener.onFailure(LicenseUtils.newComplianceException(XPackPlugin.MACHINE_LEARNING));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -5,50 +5,28 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.ResourceNotFoundException;
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
||||||
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
||||||
import org.elasticsearch.action.support.master.TransportMasterNodeAction;
|
|
||||||
import org.elasticsearch.client.Client;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
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.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.StatusToXContentObject;
|
import org.elasticsearch.common.xcontent.StatusToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.rest.RestStatus;
|
import org.elasticsearch.rest.RestStatus;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.job.JobManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.Job;
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
import org.elasticsearch.xpack.ml.job.config.JobState;
|
|
||||||
import org.elasticsearch.xpack.ml.job.messages.Messages;
|
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobDataCountsPersister;
|
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobDataDeleter;
|
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobProvider;
|
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.state.ModelSnapshot;
|
import org.elasticsearch.xpack.ml.job.process.autodetect.state.ModelSnapshot;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class RevertModelSnapshotAction
|
public class RevertModelSnapshotAction
|
||||||
extends Action<RevertModelSnapshotAction.Request, RevertModelSnapshotAction.Response, RevertModelSnapshotAction.RequestBuilder> {
|
extends Action<RevertModelSnapshotAction.Request, RevertModelSnapshotAction.Response, RevertModelSnapshotAction.RequestBuilder> {
|
||||||
@ -250,128 +228,4 @@ extends Action<RevertModelSnapshotAction.Request, RevertModelSnapshotAction.Resp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends TransportMasterNodeAction<Request, Response> {
|
|
||||||
|
|
||||||
private final Client client;
|
|
||||||
private final JobManager jobManager;
|
|
||||||
private final JobProvider jobProvider;
|
|
||||||
private final JobDataCountsPersister jobDataCountsPersister;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, ThreadPool threadPool, TransportService transportService, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver, JobManager jobManager, JobProvider jobProvider,
|
|
||||||
ClusterService clusterService, Client client, JobDataCountsPersister jobDataCountsPersister) {
|
|
||||||
super(settings, NAME, transportService, clusterService, threadPool, actionFilters, indexNameExpressionResolver, Request::new);
|
|
||||||
this.client = client;
|
|
||||||
this.jobManager = jobManager;
|
|
||||||
this.jobProvider = jobProvider;
|
|
||||||
this.jobDataCountsPersister = jobDataCountsPersister;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String executor() {
|
|
||||||
return ThreadPool.Names.SAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Response newResponse() {
|
|
||||||
return new Response();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void masterOperation(Request request, ClusterState state, ActionListener<Response> listener) throws Exception {
|
|
||||||
logger.debug("Received request to revert to snapshot id '{}' for job '{}', deleting intervening results: {}",
|
|
||||||
request.getSnapshotId(), request.getJobId(), request.getDeleteInterveningResults());
|
|
||||||
|
|
||||||
Job job = JobManager.getJobOrThrowIfUnknown(request.getJobId(), clusterService.state());
|
|
||||||
JobState jobState = jobManager.getJobState(job.getId());
|
|
||||||
if (jobState.equals(JobState.CLOSED) == false) {
|
|
||||||
throw ExceptionsHelper.conflictStatusException(Messages.getMessage(Messages.REST_JOB_NOT_CLOSED_REVERT));
|
|
||||||
}
|
|
||||||
|
|
||||||
getModelSnapshot(request, jobProvider, modelSnapshot -> {
|
|
||||||
ActionListener<Response> wrappedListener = listener;
|
|
||||||
if (request.getDeleteInterveningResults()) {
|
|
||||||
wrappedListener = wrapDeleteOldDataListener(wrappedListener, modelSnapshot, request.getJobId());
|
|
||||||
wrappedListener = wrapRevertDataCountsListener(wrappedListener, modelSnapshot, request.getJobId());
|
|
||||||
}
|
|
||||||
jobManager.revertSnapshot(request, wrappedListener, modelSnapshot);
|
|
||||||
}, listener::onFailure);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void getModelSnapshot(Request request, JobProvider provider, Consumer<ModelSnapshot> handler,
|
|
||||||
Consumer<Exception> errorHandler) {
|
|
||||||
logger.info("Reverting to snapshot '" + request.getSnapshotId() + "'");
|
|
||||||
|
|
||||||
provider.getModelSnapshot(request.getJobId(), request.getSnapshotId(), modelSnapshot -> {
|
|
||||||
if (modelSnapshot == null) {
|
|
||||||
throw new ResourceNotFoundException(Messages.getMessage(Messages.REST_NO_SUCH_MODEL_SNAPSHOT, request.getSnapshotId(),
|
|
||||||
request.getJobId()));
|
|
||||||
}
|
|
||||||
handler.accept(modelSnapshot.result);
|
|
||||||
}, errorHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ActionListener<RevertModelSnapshotAction.Response> wrapDeleteOldDataListener(
|
|
||||||
ActionListener<RevertModelSnapshotAction.Response> listener,
|
|
||||||
ModelSnapshot modelSnapshot, String jobId) {
|
|
||||||
|
|
||||||
// If we need to delete buckets that occurred after the snapshot, we
|
|
||||||
// wrap the listener with one that invokes the OldDataRemover on
|
|
||||||
// acknowledged responses
|
|
||||||
return ActionListener.wrap(response -> {
|
|
||||||
if (response.isAcknowledged()) {
|
|
||||||
Date deleteAfter = modelSnapshot.getLatestResultTimeStamp();
|
|
||||||
logger.debug("Removing intervening records: last record: " + deleteAfter + ", last result: "
|
|
||||||
+ modelSnapshot.getLatestResultTimeStamp());
|
|
||||||
|
|
||||||
logger.info("Deleting results after '" + deleteAfter + "'");
|
|
||||||
|
|
||||||
JobDataDeleter dataDeleter = new JobDataDeleter(client, jobId);
|
|
||||||
dataDeleter.deleteResultsFromTime(deleteAfter.getTime() + 1, new ActionListener<Boolean>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Boolean success) {
|
|
||||||
listener.onResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Exception e) {
|
|
||||||
listener.onFailure(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}, listener::onFailure);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ActionListener<RevertModelSnapshotAction.Response> wrapRevertDataCountsListener(
|
|
||||||
ActionListener<RevertModelSnapshotAction.Response> listener,
|
|
||||||
ModelSnapshot modelSnapshot, String jobId) {
|
|
||||||
|
|
||||||
|
|
||||||
return ActionListener.wrap(response -> {
|
|
||||||
if (response.isAcknowledged()) {
|
|
||||||
jobProvider.dataCounts(jobId, counts -> {
|
|
||||||
counts.setLatestRecordTimeStamp(modelSnapshot.getLatestRecordTimeStamp());
|
|
||||||
jobDataCountsPersister.persistDataCounts(jobId, counts, new ActionListener<Boolean>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(Boolean aBoolean) {
|
|
||||||
listener.onResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Exception e) {
|
|
||||||
listener.onFailure(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}, listener::onFailure);
|
|
||||||
}
|
|
||||||
}, listener::onFailure);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ClusterBlockException checkBlock(Request request, ClusterState state) {
|
|
||||||
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
@ -0,0 +1,327 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticsearchParseException;
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.ValidateActions;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedResponse;
|
||||||
|
import org.elasticsearch.action.support.master.MasterNodeRequest;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
import org.elasticsearch.common.ParseField;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.common.joda.DateMathParser;
|
||||||
|
import org.elasticsearch.common.unit.TimeValue;
|
||||||
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContent;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.index.mapper.DateFieldMapper;
|
||||||
|
import org.elasticsearch.xpack.ml.datafeed.DatafeedConfig;
|
||||||
|
import org.elasticsearch.xpack.ml.job.messages.Messages;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
import org.elasticsearch.xpack.persistent.PersistentTaskParams;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.LongSupplier;
|
||||||
|
|
||||||
|
public class StartDatafeedAction
|
||||||
|
extends Action<StartDatafeedAction.Request, StartDatafeedAction.Response, StartDatafeedAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final ParseField START_TIME = new ParseField("start");
|
||||||
|
public static final ParseField END_TIME = new ParseField("end");
|
||||||
|
public static final ParseField TIMEOUT = new ParseField("timeout");
|
||||||
|
|
||||||
|
public static final StartDatafeedAction INSTANCE = new StartDatafeedAction();
|
||||||
|
public static final String NAME = "cluster:admin/xpack/ml/datafeed/start";
|
||||||
|
public static final String TASK_NAME = "xpack/ml/datafeed";
|
||||||
|
|
||||||
|
private StartDatafeedAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends MasterNodeRequest<Request> implements ToXContentObject {
|
||||||
|
|
||||||
|
public static Request fromXContent(XContentParser parser) {
|
||||||
|
return parseRequest(null, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Request parseRequest(String datafeedId, XContentParser parser) {
|
||||||
|
DatafeedParams params = DatafeedParams.PARSER.apply(parser, null);
|
||||||
|
if (datafeedId != null) {
|
||||||
|
params.datafeedId = datafeedId;
|
||||||
|
}
|
||||||
|
return new Request(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private DatafeedParams params;
|
||||||
|
|
||||||
|
public Request(String datafeedId, long startTime) {
|
||||||
|
this.params = new DatafeedParams(datafeedId, startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Request(String datafeedId, String startTime) {
|
||||||
|
this.params = new DatafeedParams(datafeedId, startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Request(DatafeedParams params) {
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Request(StreamInput in) throws IOException {
|
||||||
|
readFrom(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatafeedParams getParams() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
ActionRequestValidationException e = null;
|
||||||
|
if (params.endTime != null && params.endTime <= params.startTime) {
|
||||||
|
e = ValidateActions.addValidationError(START_TIME.getPreferredName() + " ["
|
||||||
|
+ params.startTime + "] must be earlier than " + END_TIME.getPreferredName()
|
||||||
|
+ " [" + params.endTime + "]", e);
|
||||||
|
}
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
params = new DatafeedParams(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
params.writeTo(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
this.params.toXContent(builder, params);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Request other = (Request) obj;
|
||||||
|
return Objects.equals(params, other.params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class DatafeedParams implements PersistentTaskParams {
|
||||||
|
|
||||||
|
public static ObjectParser<DatafeedParams, Void> PARSER = new ObjectParser<>(TASK_NAME, DatafeedParams::new);
|
||||||
|
|
||||||
|
static {
|
||||||
|
PARSER.declareString((params, datafeedId) -> params.datafeedId = datafeedId, DatafeedConfig.ID);
|
||||||
|
PARSER.declareString((params, startTime) -> params.startTime = parseDateOrThrow(
|
||||||
|
startTime, START_TIME, System::currentTimeMillis), START_TIME);
|
||||||
|
PARSER.declareString(DatafeedParams::setEndTime, END_TIME);
|
||||||
|
PARSER.declareString((params, val) ->
|
||||||
|
params.setTimeout(TimeValue.parseTimeValue(val, TIMEOUT.getPreferredName())), TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static long parseDateOrThrow(String date, ParseField paramName, LongSupplier now) {
|
||||||
|
DateMathParser dateMathParser = new DateMathParser(DateFieldMapper.DEFAULT_DATE_TIME_FORMATTER);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return dateMathParser.parse(date, now);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String msg = Messages.getMessage(Messages.REST_INVALID_DATETIME_PARAMS, paramName.getPreferredName(), date);
|
||||||
|
throw new ElasticsearchParseException(msg, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DatafeedParams fromXContent(XContentParser parser) {
|
||||||
|
return parseRequest(null, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DatafeedParams parseRequest(String datafeedId, XContentParser parser) {
|
||||||
|
DatafeedParams params = PARSER.apply(parser, null);
|
||||||
|
if (datafeedId != null) {
|
||||||
|
params.datafeedId = datafeedId;
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatafeedParams(String datafeedId, long startTime) {
|
||||||
|
this.datafeedId = ExceptionsHelper.requireNonNull(datafeedId, DatafeedConfig.ID.getPreferredName());
|
||||||
|
this.startTime = startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatafeedParams(String datafeedId, String startTime) {
|
||||||
|
this(datafeedId, parseDateOrThrow(startTime, START_TIME, System::currentTimeMillis));
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatafeedParams(StreamInput in) throws IOException {
|
||||||
|
datafeedId = in.readString();
|
||||||
|
startTime = in.readVLong();
|
||||||
|
endTime = in.readOptionalLong();
|
||||||
|
timeout = TimeValue.timeValueMillis(in.readVLong());
|
||||||
|
}
|
||||||
|
|
||||||
|
DatafeedParams() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private String datafeedId;
|
||||||
|
private long startTime;
|
||||||
|
private Long endTime;
|
||||||
|
private TimeValue timeout = TimeValue.timeValueSeconds(20);
|
||||||
|
|
||||||
|
public String getDatafeedId() {
|
||||||
|
return datafeedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getStartTime() {
|
||||||
|
return startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getEndTime() {
|
||||||
|
return endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndTime(String endTime) {
|
||||||
|
setEndTime(parseDateOrThrow(endTime, END_TIME, System::currentTimeMillis));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndTime(Long endTime) {
|
||||||
|
this.endTime = endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeValue getTimeout() {
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTimeout(TimeValue timeout) {
|
||||||
|
this.timeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getWriteableName() {
|
||||||
|
return TASK_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
out.writeString(datafeedId);
|
||||||
|
out.writeVLong(startTime);
|
||||||
|
out.writeOptionalLong(endTime);
|
||||||
|
out.writeVLong(timeout.millis());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, ToXContent.Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
builder.field(DatafeedConfig.ID.getPreferredName(), datafeedId);
|
||||||
|
builder.field(START_TIME.getPreferredName(), String.valueOf(startTime));
|
||||||
|
if (endTime != null) {
|
||||||
|
builder.field(END_TIME.getPreferredName(), String.valueOf(endTime));
|
||||||
|
}
|
||||||
|
builder.field(TIMEOUT.getPreferredName(), timeout.getStringRep());
|
||||||
|
builder.endObject();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(datafeedId, startTime, endTime, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
DatafeedParams other = (DatafeedParams) obj;
|
||||||
|
return Objects.equals(datafeedId, other.datafeedId) &&
|
||||||
|
Objects.equals(startTime, other.startTime) &&
|
||||||
|
Objects.equals(endTime, other.endTime) &&
|
||||||
|
Objects.equals(timeout, other.timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends AcknowledgedResponse {
|
||||||
|
public Response() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response(boolean acknowledged) {
|
||||||
|
super(acknowledged);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
readAcknowledged(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
writeAcknowledged(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
AcknowledgedResponse that = (AcknowledgedResponse) o;
|
||||||
|
return isAcknowledged() == that.isAcknowledged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(isAcknowledged());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
RequestBuilder(ElasticsearchClient client, StartDatafeedAction action) {
|
||||||
|
super(client, action, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface DatafeedTaskMatcher {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,245 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.Version;
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.support.tasks.BaseTasksRequest;
|
||||||
|
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
import org.elasticsearch.common.ParseField;
|
||||||
|
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.ObjectParser;
|
||||||
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.tasks.Task;
|
||||||
|
import org.elasticsearch.xpack.ml.MLMetadataField;
|
||||||
|
import org.elasticsearch.xpack.ml.datafeed.DatafeedConfig;
|
||||||
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class StopDatafeedAction
|
||||||
|
extends Action<StopDatafeedAction.Request, StopDatafeedAction.Response, StopDatafeedAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final StopDatafeedAction INSTANCE = new StopDatafeedAction();
|
||||||
|
public static final String NAME = "cluster:admin/xpack/ml/datafeed/stop";
|
||||||
|
public static final TimeValue DEFAULT_TIMEOUT = TimeValue.timeValueMinutes(5);
|
||||||
|
|
||||||
|
private StopDatafeedAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response newResponse() {
|
||||||
|
return new Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends BaseTasksRequest<Request> implements ToXContentObject {
|
||||||
|
|
||||||
|
public static final ParseField TIMEOUT = new ParseField("timeout");
|
||||||
|
public static final ParseField FORCE = new ParseField("force");
|
||||||
|
public static final ParseField ALLOW_NO_DATAFEEDS = new ParseField("allow_no_datafeeds");
|
||||||
|
|
||||||
|
public static ObjectParser<Request, Void> PARSER = new ObjectParser<>(NAME, Request::new);
|
||||||
|
|
||||||
|
static {
|
||||||
|
PARSER.declareString((request, datafeedId) -> request.datafeedId = datafeedId, DatafeedConfig.ID);
|
||||||
|
PARSER.declareString((request, val) ->
|
||||||
|
request.setStopTimeout(TimeValue.parseTimeValue(val, TIMEOUT.getPreferredName())), TIMEOUT);
|
||||||
|
PARSER.declareBoolean(Request::setForce, FORCE);
|
||||||
|
PARSER.declareBoolean(Request::setAllowNoDatafeeds, ALLOW_NO_DATAFEEDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Request fromXContent(XContentParser parser) {
|
||||||
|
return parseRequest(null, parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Request parseRequest(String datafeedId, XContentParser parser) {
|
||||||
|
Request request = PARSER.apply(parser, null);
|
||||||
|
if (datafeedId != null) {
|
||||||
|
request.datafeedId = datafeedId;
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String datafeedId;
|
||||||
|
private String[] resolvedStartedDatafeedIds;
|
||||||
|
private TimeValue stopTimeout = DEFAULT_TIMEOUT;
|
||||||
|
private boolean force = false;
|
||||||
|
private boolean allowNoDatafeeds = true;
|
||||||
|
|
||||||
|
public Request(String datafeedId) {
|
||||||
|
this.datafeedId = ExceptionsHelper.requireNonNull(datafeedId, DatafeedConfig.ID.getPreferredName());
|
||||||
|
this.resolvedStartedDatafeedIds = new String[] { datafeedId };
|
||||||
|
}
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
}
|
||||||
|
|
||||||
|
String getDatafeedId() {
|
||||||
|
return datafeedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] getResolvedStartedDatafeedIds() {
|
||||||
|
return resolvedStartedDatafeedIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setResolvedStartedDatafeedIds(String[] resolvedStartedDatafeedIds) {
|
||||||
|
this.resolvedStartedDatafeedIds = resolvedStartedDatafeedIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeValue getStopTimeout() {
|
||||||
|
return stopTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStopTimeout(TimeValue stopTimeout) {
|
||||||
|
this.stopTimeout = ExceptionsHelper.requireNonNull(stopTimeout, TIMEOUT.getPreferredName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isForce() {
|
||||||
|
return force;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForce(boolean force) {
|
||||||
|
this.force = force;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean allowNoDatafeeds() {
|
||||||
|
return allowNoDatafeeds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowNoDatafeeds(boolean allowNoDatafeeds) {
|
||||||
|
this.allowNoDatafeeds = allowNoDatafeeds;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean match(Task task) {
|
||||||
|
for (String id : resolvedStartedDatafeedIds) {
|
||||||
|
String expectedDescription = MLMetadataField.datafeedTaskId(id);
|
||||||
|
if (task instanceof StartDatafeedAction.DatafeedTaskMatcher && expectedDescription.equals(task.getDescription())){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
datafeedId = in.readString();
|
||||||
|
resolvedStartedDatafeedIds = in.readStringArray();
|
||||||
|
stopTimeout = new TimeValue(in);
|
||||||
|
force = in.readBoolean();
|
||||||
|
if (in.getVersion().onOrAfter(Version.V_6_1_0)) {
|
||||||
|
allowNoDatafeeds = in.readBoolean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeString(datafeedId);
|
||||||
|
out.writeStringArray(resolvedStartedDatafeedIds);
|
||||||
|
stopTimeout.writeTo(out);
|
||||||
|
out.writeBoolean(force);
|
||||||
|
if (out.getVersion().onOrAfter(Version.V_6_1_0)) {
|
||||||
|
out.writeBoolean(allowNoDatafeeds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(datafeedId, stopTimeout, force, allowNoDatafeeds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject();
|
||||||
|
builder.field(DatafeedConfig.ID.getPreferredName(), datafeedId);
|
||||||
|
builder.field(TIMEOUT.getPreferredName(), stopTimeout.getStringRep());
|
||||||
|
builder.field(FORCE.getPreferredName(), force);
|
||||||
|
builder.field(ALLOW_NO_DATAFEEDS.getPreferredName(), allowNoDatafeeds);
|
||||||
|
builder.endObject();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (getClass() != obj.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Request other = (Request) obj;
|
||||||
|
return Objects.equals(datafeedId, other.datafeedId) &&
|
||||||
|
Objects.equals(stopTimeout, other.stopTimeout) &&
|
||||||
|
Objects.equals(force, other.force) &&
|
||||||
|
Objects.equals(allowNoDatafeeds, other.allowNoDatafeeds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Response extends BaseTasksResponse implements Writeable {
|
||||||
|
|
||||||
|
private boolean stopped;
|
||||||
|
|
||||||
|
public Response(boolean stopped) {
|
||||||
|
super(null, null);
|
||||||
|
this.stopped = stopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response(StreamInput in) throws IOException {
|
||||||
|
super(null, null);
|
||||||
|
readFrom(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response() {
|
||||||
|
super(null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isStopped() {
|
||||||
|
return stopped;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
stopped = in.readBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
out.writeBoolean(stopped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class RequestBuilder extends ActionRequestBuilder<Request, Response, RequestBuilder> {
|
||||||
|
|
||||||
|
RequestBuilder(ElasticsearchClient client, StopDatafeedAction action) {
|
||||||
|
super(client, action, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -22,6 +22,7 @@ import org.elasticsearch.common.io.stream.StreamOutput;
|
|||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
import org.elasticsearch.threadpool.ThreadPool;
|
||||||
import org.elasticsearch.transport.TransportService;
|
import org.elasticsearch.transport.TransportService;
|
||||||
|
import org.elasticsearch.xpack.ml.MLMetadataField;
|
||||||
import org.elasticsearch.xpack.ml.MlMetadata;
|
import org.elasticsearch.xpack.ml.MlMetadata;
|
||||||
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
import org.elasticsearch.xpack.ml.calendars.Calendar;
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobProvider;
|
import org.elasticsearch.xpack.ml.job.persistence.JobProvider;
|
||||||
@ -126,43 +127,5 @@ public class UpdateCalendarJobAction extends Action<UpdateCalendarJobAction.Requ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends HandledTransportAction<Request, PutCalendarAction.Response> {
|
|
||||||
|
|
||||||
private final ClusterService clusterService;
|
|
||||||
private final JobProvider jobProvider;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, ThreadPool threadPool,
|
|
||||||
TransportService transportService, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
ClusterService clusterService, JobProvider jobProvider) {
|
|
||||||
super(settings, NAME, threadPool, transportService, actionFilters,
|
|
||||||
indexNameExpressionResolver, Request::new);
|
|
||||||
this.clusterService = clusterService;
|
|
||||||
this.jobProvider = jobProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Request request, ActionListener<PutCalendarAction.Response> listener) {
|
|
||||||
ClusterState state = clusterService.state();
|
|
||||||
MlMetadata mlMetadata = state.getMetaData().custom(MlMetadata.TYPE);
|
|
||||||
for (String jobToAdd: request.getJobIdsToAdd()) {
|
|
||||||
if (mlMetadata.isGroupOrJob(jobToAdd) == false) {
|
|
||||||
listener.onFailure(ExceptionsHelper.missingJobException(jobToAdd));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String jobToRemove: request.getJobIdsToRemove()) {
|
|
||||||
if (mlMetadata.isGroupOrJob(jobToRemove) == false) {
|
|
||||||
listener.onFailure(ExceptionsHelper.missingJobException(jobToRemove));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jobProvider.updateCalendar(request.getCalendarId(), request.getJobIdsToAdd(), request.getJobIdsToRemove(),
|
|
||||||
c -> listener.onResponse(new PutCalendarAction.Response(c)), listener::onFailure);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* 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.ml.action;
|
||||||
|
|
||||||
|
import org.elasticsearch.action.Action;
|
||||||
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
||||||
|
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
||||||
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
|
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.common.xcontent.XContentParser;
|
||||||
|
import org.elasticsearch.xpack.ml.datafeed.DatafeedUpdate;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class UpdateDatafeedAction extends Action<UpdateDatafeedAction.Request, PutDatafeedAction.Response,
|
||||||
|
UpdateDatafeedAction.RequestBuilder> {
|
||||||
|
|
||||||
|
public static final UpdateDatafeedAction INSTANCE = new UpdateDatafeedAction();
|
||||||
|
public static final String NAME = "cluster:admin/xpack/ml/datafeeds/update";
|
||||||
|
|
||||||
|
private UpdateDatafeedAction() {
|
||||||
|
super(NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RequestBuilder newRequestBuilder(ElasticsearchClient client) {
|
||||||
|
return new RequestBuilder(client, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PutDatafeedAction.Response newResponse() {
|
||||||
|
return new PutDatafeedAction.Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Request extends AcknowledgedRequest<Request> implements ToXContentObject {
|
||||||
|
|
||||||
|
public static Request parseRequest(String datafeedId, XContentParser parser) {
|
||||||
|
DatafeedUpdate.Builder update = DatafeedUpdate.PARSER.apply(parser, null);
|
||||||
|
update.setId(datafeedId);
|
||||||
|
return new Request(update.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private DatafeedUpdate update;
|
||||||
|
|
||||||
|
public Request(DatafeedUpdate update) {
|
||||||
|
this.update = update;
|
||||||
|
}
|
||||||
|
|
||||||
|
Request() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatafeedUpdate getUpdate() {
|
||||||
|
return update;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActionRequestValidationException validate() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFrom(StreamInput in) throws IOException {
|
||||||
|
super.readFrom(in);
|
||||||
|
update = new DatafeedUpdate(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
super.writeTo(out);
|
||||||
|
update.writeTo(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
update.toXContent(builder, params);
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
Request request = (Request) o;
|
||||||
|
return Objects.equals(update, request.update);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RequestBuilder extends MasterNodeOperationRequestBuilder<Request, PutDatafeedAction.Response, RequestBuilder> {
|
||||||
|
|
||||||
|
public RequestBuilder(ElasticsearchClient client, UpdateDatafeedAction action) {
|
||||||
|
super(client, action, new Request());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -6,30 +6,16 @@
|
|||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
import org.elasticsearch.action.support.master.AcknowledgedRequest;
|
||||||
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
|
||||||
import org.elasticsearch.action.support.master.TransportMasterNodeAction;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
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.metadata.MetaData;
|
|
||||||
import org.elasticsearch.cluster.service.ClusterService;
|
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.job.JobManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.JobUpdate;
|
import org.elasticsearch.xpack.ml.job.config.JobUpdate;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -132,42 +118,4 @@ public class UpdateJobAction extends Action<UpdateJobAction.Request, PutJobActio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends TransportMasterNodeAction<UpdateJobAction.Request, PutJobAction.Response> {
|
|
||||||
|
|
||||||
private final JobManager jobManager;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, TransportService transportService, ClusterService clusterService,
|
|
||||||
ThreadPool threadPool, ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
JobManager jobManager) {
|
|
||||||
super(settings, UpdateJobAction.NAME, transportService, clusterService, threadPool, actionFilters,
|
|
||||||
indexNameExpressionResolver, UpdateJobAction.Request::new);
|
|
||||||
this.jobManager = jobManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String executor() {
|
|
||||||
return ThreadPool.Names.SAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected PutJobAction.Response newResponse() {
|
|
||||||
return new PutJobAction.Response();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void masterOperation(Request request, ClusterState state,
|
|
||||||
ActionListener<PutJobAction.Response> listener) throws Exception {
|
|
||||||
if (request.getJobId().equals(MetaData.ALL)) {
|
|
||||||
throw new IllegalArgumentException("Job Id " + MetaData.ALL + " cannot be for update");
|
|
||||||
}
|
|
||||||
|
|
||||||
jobManager.updateJob(request.getJobId(), request.getJobUpdate(), request, listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ClusterBlockException checkBlock(UpdateJobAction.Request request, ClusterState state) {
|
|
||||||
return state.blocks().globalBlockedException(ClusterBlockLevel.METADATA_WRITE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -5,53 +5,29 @@
|
|||||||
*/
|
*/
|
||||||
package org.elasticsearch.xpack.ml.action;
|
package org.elasticsearch.xpack.ml.action;
|
||||||
|
|
||||||
import org.elasticsearch.ResourceNotFoundException;
|
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequest;
|
import org.elasticsearch.action.ActionRequest;
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
import org.elasticsearch.action.ActionResponse;
|
import org.elasticsearch.action.ActionResponse;
|
||||||
import org.elasticsearch.action.bulk.BulkAction;
|
|
||||||
import org.elasticsearch.action.bulk.BulkRequestBuilder;
|
|
||||||
import org.elasticsearch.action.bulk.BulkResponse;
|
|
||||||
import org.elasticsearch.action.index.IndexRequest;
|
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.HandledTransportAction;
|
|
||||||
import org.elasticsearch.action.support.WriteRequest;
|
|
||||||
import org.elasticsearch.client.Client;
|
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
|
|
||||||
import org.elasticsearch.common.ParseField;
|
import org.elasticsearch.common.ParseField;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.ObjectParser;
|
import org.elasticsearch.common.xcontent.ObjectParser;
|
||||||
import org.elasticsearch.common.xcontent.StatusToXContentObject;
|
import org.elasticsearch.common.xcontent.StatusToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.ToXContent;
|
|
||||||
import org.elasticsearch.common.xcontent.ToXContentObject;
|
import org.elasticsearch.common.xcontent.ToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.rest.RestStatus;
|
import org.elasticsearch.rest.RestStatus;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.Job;
|
import org.elasticsearch.xpack.ml.job.config.Job;
|
||||||
import org.elasticsearch.xpack.ml.job.messages.Messages;
|
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.ElasticsearchMappings;
|
|
||||||
import org.elasticsearch.xpack.ml.job.persistence.JobProvider;
|
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.state.ModelSnapshot;
|
import org.elasticsearch.xpack.ml.job.process.autodetect.state.ModelSnapshot;
|
||||||
import org.elasticsearch.xpack.ml.job.results.Result;
|
import org.elasticsearch.xpack.ml.job.process.autodetect.state.ModelSnapshotField;
|
||||||
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
import org.elasticsearch.xpack.ml.utils.ExceptionsHelper;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
import static org.elasticsearch.xpack.ClientHelper.ML_ORIGIN;
|
|
||||||
import static org.elasticsearch.xpack.ClientHelper.executeAsyncWithOrigin;
|
|
||||||
|
|
||||||
public class UpdateModelSnapshotAction extends Action<UpdateModelSnapshotAction.Request,
|
public class UpdateModelSnapshotAction extends Action<UpdateModelSnapshotAction.Request,
|
||||||
UpdateModelSnapshotAction.Response, UpdateModelSnapshotAction.RequestBuilder> {
|
UpdateModelSnapshotAction.Response, UpdateModelSnapshotAction.RequestBuilder> {
|
||||||
@ -79,7 +55,7 @@ public class UpdateModelSnapshotAction extends Action<UpdateModelSnapshotAction.
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
PARSER.declareString((request, jobId) -> request.jobId = jobId, Job.ID);
|
PARSER.declareString((request, jobId) -> request.jobId = jobId, Job.ID);
|
||||||
PARSER.declareString((request, snapshotId) -> request.snapshotId = snapshotId, ModelSnapshot.SNAPSHOT_ID);
|
PARSER.declareString((request, snapshotId) -> request.snapshotId = snapshotId, ModelSnapshotField.SNAPSHOT_ID);
|
||||||
PARSER.declareString(Request::setDescription, ModelSnapshot.DESCRIPTION);
|
PARSER.declareString(Request::setDescription, ModelSnapshot.DESCRIPTION);
|
||||||
PARSER.declareBoolean(Request::setRetain, ModelSnapshot.RETAIN);
|
PARSER.declareBoolean(Request::setRetain, ModelSnapshot.RETAIN);
|
||||||
}
|
}
|
||||||
@ -105,7 +81,7 @@ public class UpdateModelSnapshotAction extends Action<UpdateModelSnapshotAction.
|
|||||||
|
|
||||||
public Request(String jobId, String snapshotId) {
|
public Request(String jobId, String snapshotId) {
|
||||||
this.jobId = ExceptionsHelper.requireNonNull(jobId, Job.ID.getPreferredName());
|
this.jobId = ExceptionsHelper.requireNonNull(jobId, Job.ID.getPreferredName());
|
||||||
this.snapshotId = ExceptionsHelper.requireNonNull(snapshotId, ModelSnapshot.SNAPSHOT_ID.getPreferredName());
|
this.snapshotId = ExceptionsHelper.requireNonNull(snapshotId, ModelSnapshotField.SNAPSHOT_ID.getPreferredName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getJobId() {
|
public String getJobId() {
|
||||||
@ -159,7 +135,7 @@ public class UpdateModelSnapshotAction extends Action<UpdateModelSnapshotAction.
|
|||||||
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
builder.startObject();
|
builder.startObject();
|
||||||
builder.field(Job.ID.getPreferredName(), jobId);
|
builder.field(Job.ID.getPreferredName(), jobId);
|
||||||
builder.field(ModelSnapshot.SNAPSHOT_ID.getPreferredName(), snapshotId);
|
builder.field(ModelSnapshotField.SNAPSHOT_ID.getPreferredName(), snapshotId);
|
||||||
if (description != null) {
|
if (description != null) {
|
||||||
builder.field(ModelSnapshot.DESCRIPTION.getPreferredName(), description);
|
builder.field(ModelSnapshot.DESCRIPTION.getPreferredName(), description);
|
||||||
}
|
}
|
||||||
@ -267,73 +243,4 @@ public class UpdateModelSnapshotAction extends Action<UpdateModelSnapshotAction.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends HandledTransportAction<Request, Response> {
|
|
||||||
|
|
||||||
private final JobProvider jobProvider;
|
|
||||||
private final Client client;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, TransportService transportService, ThreadPool threadPool, ActionFilters actionFilters,
|
|
||||||
IndexNameExpressionResolver indexNameExpressionResolver, JobProvider jobProvider, Client client) {
|
|
||||||
super(settings, NAME, threadPool, transportService, actionFilters, indexNameExpressionResolver, Request::new);
|
|
||||||
this.jobProvider = jobProvider;
|
|
||||||
this.client = client;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void doExecute(Request request, ActionListener<Response> listener) {
|
|
||||||
logger.debug("Received request to update model snapshot [{}] for job [{}]", request.getSnapshotId(), request.getJobId());
|
|
||||||
jobProvider.getModelSnapshot(request.getJobId(), request.getSnapshotId(), modelSnapshot -> {
|
|
||||||
if (modelSnapshot == null) {
|
|
||||||
listener.onFailure(new ResourceNotFoundException(Messages.getMessage(
|
|
||||||
Messages.REST_NO_SUCH_MODEL_SNAPSHOT, request.getSnapshotId(), request.getJobId())));
|
|
||||||
} else {
|
|
||||||
Result<ModelSnapshot> updatedSnapshot = applyUpdate(request, modelSnapshot);
|
|
||||||
indexModelSnapshot(updatedSnapshot, b -> {
|
|
||||||
// The quantiles can be large, and totally dominate the output -
|
|
||||||
// it's clearer to remove them
|
|
||||||
listener.onResponse(new Response(new ModelSnapshot.Builder(updatedSnapshot.result).setQuantiles(null).build()));
|
|
||||||
}, listener::onFailure);
|
|
||||||
}
|
|
||||||
}, listener::onFailure);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Result<ModelSnapshot> applyUpdate(Request request, Result<ModelSnapshot> target) {
|
|
||||||
ModelSnapshot.Builder updatedSnapshotBuilder = new ModelSnapshot.Builder(target.result);
|
|
||||||
if (request.getDescription() != null) {
|
|
||||||
updatedSnapshotBuilder.setDescription(request.getDescription());
|
|
||||||
}
|
|
||||||
if (request.getRetain() != null) {
|
|
||||||
updatedSnapshotBuilder.setRetain(request.getRetain());
|
|
||||||
}
|
|
||||||
return new Result(target.index, updatedSnapshotBuilder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void indexModelSnapshot(Result<ModelSnapshot> modelSnapshot, Consumer<Boolean> handler, Consumer<Exception> errorHandler) {
|
|
||||||
IndexRequest indexRequest = new IndexRequest(modelSnapshot.index, ElasticsearchMappings.DOC_TYPE,
|
|
||||||
ModelSnapshot.documentId(modelSnapshot.result));
|
|
||||||
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
|
||||||
modelSnapshot.result.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
|
||||||
indexRequest.source(builder);
|
|
||||||
} catch (IOException e) {
|
|
||||||
errorHandler.accept(e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
BulkRequestBuilder bulkRequestBuilder = client.prepareBulk();
|
|
||||||
bulkRequestBuilder.add(indexRequest);
|
|
||||||
bulkRequestBuilder.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
|
|
||||||
executeAsyncWithOrigin(client, ML_ORIGIN, BulkAction.INSTANCE, bulkRequestBuilder.request(),
|
|
||||||
new ActionListener<BulkResponse>() {
|
|
||||||
@Override
|
|
||||||
public void onResponse(BulkResponse indexResponse) {
|
|
||||||
handler.accept(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onFailure(Exception e) {
|
|
||||||
errorHandler.accept(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -7,28 +7,17 @@ package org.elasticsearch.xpack.ml.action;
|
|||||||
|
|
||||||
import org.elasticsearch.Version;
|
import org.elasticsearch.Version;
|
||||||
import org.elasticsearch.action.Action;
|
import org.elasticsearch.action.Action;
|
||||||
import org.elasticsearch.action.ActionListener;
|
|
||||||
import org.elasticsearch.action.ActionRequestBuilder;
|
import org.elasticsearch.action.ActionRequestBuilder;
|
||||||
import org.elasticsearch.action.support.ActionFilters;
|
|
||||||
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
import org.elasticsearch.action.support.tasks.BaseTasksResponse;
|
||||||
import org.elasticsearch.client.ElasticsearchClient;
|
import org.elasticsearch.client.ElasticsearchClient;
|
||||||
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.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Writeable;
|
import org.elasticsearch.common.io.stream.Writeable;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
|
||||||
import org.elasticsearch.common.xcontent.StatusToXContentObject;
|
import org.elasticsearch.common.xcontent.StatusToXContentObject;
|
||||||
import org.elasticsearch.common.xcontent.XContentBuilder;
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
import org.elasticsearch.rest.RestStatus;
|
import org.elasticsearch.rest.RestStatus;
|
||||||
import org.elasticsearch.threadpool.ThreadPool;
|
|
||||||
import org.elasticsearch.transport.TransportService;
|
|
||||||
import org.elasticsearch.xpack.ml.calendars.SpecialEvent;
|
|
||||||
import org.elasticsearch.xpack.ml.job.config.JobUpdate;
|
import org.elasticsearch.xpack.ml.job.config.JobUpdate;
|
||||||
import org.elasticsearch.xpack.ml.job.config.ModelPlotConfig;
|
import org.elasticsearch.xpack.ml.job.config.ModelPlotConfig;
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.AutodetectProcessManager;
|
|
||||||
import org.elasticsearch.xpack.ml.job.process.autodetect.UpdateParams;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -65,7 +54,7 @@ public class UpdateProcessAction extends
|
|||||||
|
|
||||||
private boolean isUpdated;
|
private boolean isUpdated;
|
||||||
|
|
||||||
private Response() {
|
Response() {
|
||||||
super(null, null);
|
super(null, null);
|
||||||
this.isUpdated = true;
|
this.isUpdated = true;
|
||||||
}
|
}
|
||||||
@ -118,7 +107,7 @@ public class UpdateProcessAction extends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Request extends TransportJobTaskAction.JobTaskRequest<Request> {
|
public static class Request extends JobTaskRequest<Request> {
|
||||||
|
|
||||||
private ModelPlotConfig modelPlotConfig;
|
private ModelPlotConfig modelPlotConfig;
|
||||||
private List<JobUpdate.DetectorUpdate> detectorUpdates;
|
private List<JobUpdate.DetectorUpdate> detectorUpdates;
|
||||||
@ -195,40 +184,4 @@ public class UpdateProcessAction extends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TransportAction extends TransportJobTaskAction<Request, Response> {
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public TransportAction(Settings settings, TransportService transportService, ThreadPool threadPool, ClusterService clusterService,
|
|
||||||
ActionFilters actionFilters, IndexNameExpressionResolver indexNameExpressionResolver,
|
|
||||||
AutodetectProcessManager processManager) {
|
|
||||||
super(settings, NAME, threadPool, clusterService, transportService, actionFilters, indexNameExpressionResolver,
|
|
||||||
Request::new, Response::new, ThreadPool.Names.SAME, processManager);
|
|
||||||
// ThreadPool.Names.SAME, because operations is executed by autodetect worker thread
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Response readTaskResponse(StreamInput in) throws IOException {
|
|
||||||
Response response = new Response();
|
|
||||||
response.readFrom(in);
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void taskOperation(Request request, OpenJobAction.JobTask task, ActionListener<Response> listener) {
|
|
||||||
try {
|
|
||||||
processManager.writeUpdateProcessMessage(task,
|
|
||||||
new UpdateParams(request.getModelPlotConfig(),
|
|
||||||
request.getDetectorUpdates(), request.isUpdateSpecialEvents()),
|
|
||||||
e -> {
|
|
||||||
if (e == null) {
|
|
||||||
listener.onResponse(new Response());
|
|
||||||
} else {
|
|
||||||
listener.onFailure(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
|
||||||
listener.onFailure(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user