|
@@ -15,15 +15,31 @@
|
|
*/
|
|
*/
|
|
package org.codelibs.fess.app.web.admin.maintenance;
|
|
package org.codelibs.fess.app.web.admin.maintenance;
|
|
|
|
|
|
|
|
+import java.io.IOException;
|
|
|
|
+import java.net.InetAddress;
|
|
|
|
+import java.nio.file.Files;
|
|
|
|
+import java.nio.file.Path;
|
|
|
|
+import java.nio.file.Paths;
|
|
import java.text.SimpleDateFormat;
|
|
import java.text.SimpleDateFormat;
|
|
|
|
+import java.util.Arrays;
|
|
import java.util.Date;
|
|
import java.util.Date;
|
|
|
|
+import java.util.Properties;
|
|
|
|
+import java.util.stream.Stream;
|
|
|
|
+import java.util.zip.ZipEntry;
|
|
|
|
+import java.util.zip.ZipOutputStream;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
import javax.annotation.Resource;
|
|
|
|
|
|
|
|
+import org.codelibs.core.io.CopyUtil;
|
|
|
|
+import org.codelibs.core.lang.StringUtil;
|
|
|
|
+import org.codelibs.curl.CurlResponse;
|
|
import org.codelibs.fess.app.web.base.FessAdminAction;
|
|
import org.codelibs.fess.app.web.base.FessAdminAction;
|
|
import org.codelibs.fess.es.client.FessEsClient;
|
|
import org.codelibs.fess.es.client.FessEsClient;
|
|
|
|
+import org.codelibs.fess.mylasta.direction.FessConfig.SimpleImpl;
|
|
|
|
+import org.codelibs.fess.util.ComponentUtil;
|
|
import org.elasticsearch.action.ActionListener;
|
|
import org.elasticsearch.action.ActionListener;
|
|
import org.lastaflute.web.Execute;
|
|
import org.lastaflute.web.Execute;
|
|
|
|
+import org.lastaflute.web.response.ActionResponse;
|
|
import org.lastaflute.web.response.HtmlResponse;
|
|
import org.lastaflute.web.response.HtmlResponse;
|
|
import org.lastaflute.web.ruts.process.ActionRuntime;
|
|
import org.lastaflute.web.ruts.process.ActionRuntime;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.Logger;
|
|
@@ -36,6 +52,10 @@ public class AdminMaintenanceAction extends FessAdminAction {
|
|
//
|
|
//
|
|
private static final Logger logger = LoggerFactory.getLogger(AdminMaintenanceAction.class);
|
|
private static final Logger logger = LoggerFactory.getLogger(AdminMaintenanceAction.class);
|
|
|
|
|
|
|
|
+ private static final String[] ES_CAT_NAMES = new String[] { "aliases", "allocation", "count", "fielddata", "health", "indices",
|
|
|
|
+ "master", "nodeattrs", "nodes", "pending_tasks", "plugins", "recovery", "repositories", "thread_pool", "shards", "segments",
|
|
|
|
+ "snapshots", "templates" };
|
|
|
|
+
|
|
// ===================================================================================
|
|
// ===================================================================================
|
|
// Attribute
|
|
// Attribute
|
|
//
|
|
//
|
|
@@ -63,11 +83,11 @@ public class AdminMaintenanceAction extends FessAdminAction {
|
|
}
|
|
}
|
|
|
|
|
|
private HtmlResponse asIndexHtml() {
|
|
private HtmlResponse asIndexHtml() {
|
|
- return asHtml(path_AdminMaintenance_AdminMaintenanceJsp).useForm(UpgradeForm.class);
|
|
|
|
|
|
+ return asHtml(path_AdminMaintenance_AdminMaintenanceJsp).useForm(ActionForm.class);
|
|
}
|
|
}
|
|
|
|
|
|
@Execute
|
|
@Execute
|
|
- public HtmlResponse reindexOnly(final UpgradeForm form) {
|
|
|
|
|
|
+ public HtmlResponse reindexOnly(final ActionForm form) {
|
|
validate(form, messages -> {}, this::asIndexHtml);
|
|
validate(form, messages -> {}, this::asIndexHtml);
|
|
verifyToken(this::asIndexHtml);
|
|
verifyToken(this::asIndexHtml);
|
|
if (startReindex(isCheckboxEnabled(form.replaceAliases), form.numberOfShardsForDoc, form.autoExpandReplicasForDoc)) {
|
|
if (startReindex(isCheckboxEnabled(form.replaceAliases), form.numberOfShardsForDoc, form.autoExpandReplicasForDoc)) {
|
|
@@ -77,7 +97,7 @@ public class AdminMaintenanceAction extends FessAdminAction {
|
|
}
|
|
}
|
|
|
|
|
|
@Execute
|
|
@Execute
|
|
- public HtmlResponse clearCrawlerIndex(final UpgradeForm form) {
|
|
|
|
|
|
+ public HtmlResponse clearCrawlerIndex(final ActionForm form) {
|
|
validate(form, messages -> {}, this::asIndexHtml);
|
|
validate(form, messages -> {}, this::asIndexHtml);
|
|
verifyToken(this::asIndexHtml);
|
|
verifyToken(this::asIndexHtml);
|
|
fessEsClient
|
|
fessEsClient
|
|
@@ -94,7 +114,151 @@ public class AdminMaintenanceAction extends FessAdminAction {
|
|
return redirect(getClass());
|
|
return redirect(getClass());
|
|
}
|
|
}
|
|
|
|
|
|
- private boolean startReindex(final boolean replaceAliases, final String numberOfShards, final String autoExpandReplicas) {
|
|
|
|
|
|
+ @Execute
|
|
|
|
+ public ActionResponse downloadLogs(final ActionForm form) {
|
|
|
|
+ validate(form, messages -> {}, this::asIndexHtml);
|
|
|
|
+ verifyTokenKeep(this::asIndexHtml);
|
|
|
|
+
|
|
|
|
+ final String diagnosticId = "log" + new SimpleDateFormat("yyyyMMddHHmm").format(ComponentUtil.getSystemHelper().getCurrentTime());
|
|
|
|
+ return asStream(diagnosticId + ".zip").contentTypeOctetStream().stream(out -> {
|
|
|
|
+ try (ZipOutputStream zos = new ZipOutputStream(out.stream())) {
|
|
|
|
+ writeLogFiles(zos, diagnosticId);
|
|
|
|
+ writeSystemProperties(zos, diagnosticId);
|
|
|
|
+ writeFessBasicConfig(zos, diagnosticId);
|
|
|
|
+ writeFessConfig(zos, diagnosticId);
|
|
|
|
+ writeElasticsearchCat(zos, diagnosticId);
|
|
|
|
+ writeElasticsearchJson(zos, diagnosticId);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected void writeElasticsearchJson(final ZipOutputStream zos, final String id) {
|
|
|
|
+ writeElastisearchJsonApi(zos, id, "cluster", "health");
|
|
|
|
+ writeElastisearchJsonApi(zos, id, "cluster", "state");
|
|
|
|
+ writeElastisearchJsonApi(zos, id, "cluster", "stats");
|
|
|
|
+ writeElastisearchJsonApi(zos, id, "cluster", "pending_tasks");
|
|
|
|
+ writeElastisearchJsonApi(zos, id, "nodes", "stats");
|
|
|
|
+ writeElastisearchJsonApi(zos, id, "nodes", "_all");
|
|
|
|
+ writeElastisearchJsonApi(zos, id, "nodes", "usage");
|
|
|
|
+ writeElastisearchJsonApi(zos, id, "remote", "info");
|
|
|
|
+ writeElastisearchJsonApi(zos, id, "tasks", "");
|
|
|
|
+ writeElastisearchJsonApi(zos, id, "nodes", "hot_threads");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected void writeElastisearchJsonApi(final ZipOutputStream zos, final String id, final String v1, final String v2) {
|
|
|
|
+ final ZipEntry entry = new ZipEntry(id + "/es_" + v1 + "_" + v2 + ".json");
|
|
|
|
+ try {
|
|
|
|
+ zos.putNextEntry(entry);
|
|
|
|
+ try (CurlResponse response = ComponentUtil.getCurlHelper().get("/_" + v1 + "/" + v2).execute()) {
|
|
|
|
+ CopyUtil.copy(response.getContentAsStream(), zos);
|
|
|
|
+ }
|
|
|
|
+ } catch (final Exception e) {
|
|
|
|
+ logger.warn("Failed to access /_" + v1 + "/" + v2, e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected void writeElasticsearchCat(final ZipOutputStream zos, final String id) {
|
|
|
|
+ Arrays.stream(ES_CAT_NAMES).forEach(name -> {
|
|
|
|
+ final ZipEntry entry = new ZipEntry(id + "/es_cat_" + name + ".txt");
|
|
|
|
+ try {
|
|
|
|
+ zos.putNextEntry(entry);
|
|
|
|
+ try (CurlResponse response = ComponentUtil.getCurlHelper().get("/_cat/" + name).param("v", "").execute()) {
|
|
|
|
+ CopyUtil.copy(response.getContentAsStream(), zos);
|
|
|
|
+ }
|
|
|
|
+ } catch (final Exception e) {
|
|
|
|
+ logger.warn("Failed to access /_cat/" + name, e);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected void writeFessConfig(final ZipOutputStream zos, final String id) {
|
|
|
|
+ if (fessConfig instanceof SimpleImpl) {
|
|
|
|
+ final Properties prop = new Properties();
|
|
|
|
+ ((SimpleImpl) fessConfig).keySet().stream().forEach(k -> prop.setProperty(k, fessConfig.get(k)));
|
|
|
|
+
|
|
|
|
+ final ZipEntry entry = new ZipEntry(id + "/fess_config.properties");
|
|
|
|
+ try {
|
|
|
|
+ zos.putNextEntry(entry);
|
|
|
|
+ prop.store(zos, getHostInfo());
|
|
|
|
+ } catch (final IOException e) {
|
|
|
|
+ logger.warn("Failed to access system.properties.", e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected void writeFessBasicConfig(final ZipOutputStream zos, final String id) {
|
|
|
|
+ final ZipEntry entry = new ZipEntry(id + "/fess_basic_config.bulk");
|
|
|
|
+ try {
|
|
|
|
+ zos.putNextEntry(entry);
|
|
|
|
+ try (CurlResponse response =
|
|
|
|
+ ComponentUtil.getCurlHelper().get("/.fess_basic_config/_data").param("format", "json")
|
|
|
|
+ .param("scroll", fessConfig.getIndexScrollSearchTimeout()).execute()) {
|
|
|
|
+ CopyUtil.copy(response.getContentAsStream(), zos);
|
|
|
|
+ }
|
|
|
|
+ } catch (final IOException e) {
|
|
|
|
+ logger.warn("Failed to access system.properties.", e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected void writeSystemProperties(final ZipOutputStream zos, final String id) {
|
|
|
|
+ final ZipEntry entry = new ZipEntry(id + "/system.properties");
|
|
|
|
+ try {
|
|
|
|
+ zos.putNextEntry(entry);
|
|
|
|
+ ComponentUtil.getSystemProperties().store(zos, getHostInfo());
|
|
|
|
+ } catch (final IOException e) {
|
|
|
|
+ logger.warn("Failed to access system.properties.", e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected void writeLogFiles(final ZipOutputStream zos, final String id) {
|
|
|
|
+ final String logFilePath = systemHelper.getLogFilePath();
|
|
|
|
+ if (StringUtil.isNotBlank(logFilePath)) {
|
|
|
|
+ final Path logDirPath = Paths.get(logFilePath);
|
|
|
|
+ try (Stream<Path> stream = Files.list(logDirPath)) {
|
|
|
|
+ stream.filter(entry -> isLogFilename(entry.getFileName().toString())).forEach(filePath -> {
|
|
|
|
+ final ZipEntry entry = new ZipEntry(id + "/" + filePath.getFileName().toString());
|
|
|
|
+ try {
|
|
|
|
+ zos.putNextEntry(entry);
|
|
|
|
+ final long len = Files.copy(filePath, zos);
|
|
|
|
+ if (logger.isDebugEnabled()) {
|
|
|
|
+ logger.debug(filePath.getFileName() + ": " + len);
|
|
|
|
+ }
|
|
|
|
+ } catch (final IOException e) {
|
|
|
|
+ logger.warn("Failed to access " + filePath, e);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ } catch (final Exception e) {
|
|
|
|
+ logger.warn("Failed to access log files.", e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected String getHostInfo() {
|
|
|
|
+ final StringBuilder buf = new StringBuilder();
|
|
|
|
+ try {
|
|
|
|
+ final InetAddress ia = InetAddress.getLocalHost();
|
|
|
|
+ final String hostname = ia.getHostName();
|
|
|
|
+ if (StringUtil.isNotBlank(hostname)) {
|
|
|
|
+ buf.append(hostname);
|
|
|
|
+ }
|
|
|
|
+ final String ip = ia.getHostAddress();
|
|
|
|
+ if (StringUtil.isNotBlank(ip)) {
|
|
|
|
+ if (buf.length() > 0) {
|
|
|
|
+ buf.append(" : ");
|
|
|
|
+ }
|
|
|
|
+ buf.append(ip);
|
|
|
|
+ }
|
|
|
|
+ } catch (final Exception e) {
|
|
|
|
+ // ignore
|
|
|
|
+ }
|
|
|
|
+ return buf.toString();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected boolean isLogFilename(final String name) {
|
|
|
|
+ return name.endsWith(".log") || name.endsWith(".log.gz");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected boolean startReindex(final boolean replaceAliases, final String numberOfShards, final String autoExpandReplicas) {
|
|
final String docIndex = "fess";
|
|
final String docIndex = "fess";
|
|
final String fromIndex = fessConfig.getIndexDocumentUpdateIndex();
|
|
final String fromIndex = fessConfig.getIndexDocumentUpdateIndex();
|
|
final String toIndex = docIndex + "." + new SimpleDateFormat("yyyyMMddHHmm").format(new Date());
|
|
final String toIndex = docIndex + "." + new SimpleDateFormat("yyyyMMddHHmm").format(new Date());
|