/* * Copyright 2015 floragunn UG (haftungsbeschränkt) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.floragunn.searchguard.tools; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.net.InetSocketAddress; import java.net.Socket; import java.nio.charset.Charset; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.Locale; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; import org.elasticsearch.action.WriteConsistencyLevel; import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.Version; import org.elasticsearch.action.admin.cluster.health.ClusterHealthRequest; import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse; 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.NodesStatsRequest; import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest; import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest; import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; import org.elasticsearch.action.admin.cluster.tasks.PendingClusterTasksRequest; import org.elasticsearch.action.admin.cluster.tasks.PendingClusterTasksResponse; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsRequest; import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest; import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsResponse; import org.elasticsearch.action.admin.indices.stats.IndicesStatsRequest; import org.elasticsearch.action.admin.indices.stats.IndicesStatsResponse; import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.get.GetResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.client.Client; import org.elasticsearch.client.transport.NoNodeAvailableException; import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.cluster.health.ClusterHealthStatus; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.settings.loader.JsonSettingsLoader; import org.elasticsearch.common.transport.InetSocketTransportAddress; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentHelper; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.IndexNotFoundException; import com.floragunn.searchguard.SearchGuardPlugin; import com.floragunn.searchguard.action.configupdate.ConfigUpdateAction; import com.floragunn.searchguard.action.configupdate.ConfigUpdateRequest; import com.floragunn.searchguard.action.configupdate.ConfigUpdateResponse; import com.floragunn.searchguard.ssl.SearchGuardSSLPlugin; import com.floragunn.searchguard.ssl.util.SSLConfigConstants; import com.floragunn.searchguard.support.ConfigConstants; import com.google.common.io.Files; public class SearchGuardAdmin { private static final String SG_TS_PASS = "SG_TS_PASS"; private static final String SG_KS_PASS = "SG_KS_PASS"; //not used in multithreaded fashion private static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MMM-dd_HH-mm-ss", Locale.ENGLISH); private static final Settings ENABLE_ALL_ALLOCATIONS_SETTINGS = Settings.builder() .put("cluster.routing.allocation.enable", "all") .build(); public static void main(final String[] args) { try { main0(args); } catch (NoNodeAvailableException e) { System.out.println("ERR: Cannot connect to elasticsearch. Please refer to elasticsearch logfile for more information"); System.out.println("Trace:"); e.printStackTrace(); System.exit(-1); } catch (IndexNotFoundException e) { System.out.println("ERR: No searchguard configuartion index found. Pls. execute sgadmin with different command line parameters"); System.out.println("When you run it for the first time to not specify -us, -era, -dra or -rl"); System.out.println("For more informations look here: https://github.com/floragunncom/search-guard/issues/228"); System.exit(-1); } catch (Exception e) { System.out.println("ERR: An unexpected "+e.getClass().getSimpleName()+" occured: "+e.getMessage()); System.out.println("Trace:"); e.printStackTrace(); System.exit(-1); } } private static void main0(final String[] args) throws Exception { System.setProperty("sg.nowarn.client","true"); final HelpFormatter formatter = new HelpFormatter(); Options options = new Options(); options.addOption( "nhnv", "disable-host-name-verification", false, "Disable hostname verification" ); options.addOption( "nrhn", "disable-resolve-hostname", false, "Disable hostname beeing resolved" ); options.addOption(Option.builder("ts").longOpt("truststore").hasArg().argName("file").required().desc("Path to truststore (JKS/PKCS12 format)").build()); options.addOption(Option.builder("ks").longOpt("keystore").hasArg().argName("file").required().desc("Path to keystore (JKS/PKCS12 format").build()); options.addOption(Option.builder("tst").longOpt("truststore-type").hasArg().argName("type").desc("JKS or PKCS12, if not given use file ext. to dectect type").build()); options.addOption(Option.builder("kst").longOpt("keystore-type").hasArg().argName("type").desc("JKS or PKCS12, if not given use file ext. to dectect type").build()); options.addOption(Option.builder("tspass").longOpt("truststore-password").hasArg().argName("password").desc("Truststore password").build()); options.addOption(Option.builder("kspass").longOpt("keystore-password").hasArg().argName("password").desc("Keystore password").build()); options.addOption(Option.builder("cd").longOpt("configdir").hasArg().argName("directory").desc("Directory for config files").build()); options.addOption(Option.builder("h").longOpt("hostname").hasArg().argName("host").desc("Elasticsearch host").build()); options.addOption(Option.builder("p").longOpt("port").hasArg().argName("port").desc("Elasticsearch transport port (normally 9300)").build()); options.addOption(Option.builder("cn").longOpt("clustername").hasArg().argName("clustername").desc("Clustername").build()); options.addOption( "sniff", "enable-sniffing", false, "Enable client.transport.sniff" ); options.addOption( "icl", "ignore-clustername", false, "Ignore clustername" ); options.addOption(Option.builder("r").longOpt("retrieve").desc("retrieve current config").build()); options.addOption(Option.builder("f").longOpt("file").hasArg().argName("file").desc("file").build()); options.addOption(Option.builder("t").longOpt("type").hasArg().argName("file-type").desc("file-type").build()); options.addOption(Option.builder("tsalias").longOpt("truststore-alias").hasArg().argName("alias").desc("Truststore alias").build()); options.addOption(Option.builder("ksalias").longOpt("keystore-alias").hasArg().argName("alias").desc("Keystore alias").build()); options.addOption(Option.builder("ec").longOpt("enabled-ciphers").hasArg().argName("cipers").desc("Comma separated list of TLS ciphers").build()); options.addOption(Option.builder("ep").longOpt("enabled-protocols").hasArg().argName("protocols").desc("Comma separated list of TLS protocols").build()); //TODO mark as deprecated and replace it with "era" if "era" is mature enough options.addOption(Option.builder("us").longOpt("update_settings").hasArg().argName("number of replicas").desc("update the number of replicas and reload configuration on all nodes and exit").build()); options.addOption(Option.builder("i").longOpt("index").hasArg().argName("indexname").desc("The index Searchguard uses to store its configs in").build()); options.addOption(Option.builder("era").longOpt("enable-replica-autoexpand").desc("enable replica auto expand and exit").build()); options.addOption(Option.builder("dra").longOpt("disable-replica-autoexpand").desc("disable replica auto expand and exit").build()); options.addOption(Option.builder("rl").longOpt("reload").desc("reload configuration on all nodes and exit").build()); options.addOption(Option.builder("ff").longOpt("fail-fast").desc("fail-fast if something goes wrong").build()); options.addOption(Option.builder("dg").longOpt("diagnose").desc("Log diagnostic trace into a file").build()); options.addOption(Option.builder("dci").longOpt("delete-config-index").desc("Delete 'searchguard' config index and exit.").build()); options.addOption(Option.builder("esa").longOpt("enable-shard-allocation").desc("Enable all shard allocation and exit.").build()); options.addOption(Option.builder("arc").longOpt("accept-red-cluster").desc("Also operate on a red cluster. Normally we wait for yellow state.").build()); String hostname = "localhost"; int port = 9300; String kspass = System.getenv(SG_KS_PASS) != null ? System.getenv(SG_KS_PASS) : "changeit"; String tspass = System.getenv(SG_TS_PASS) != null ? System.getenv(SG_TS_PASS) : kspass; String cd = "."; String ks; String ts; String kst = null; String tst = null; boolean nhnv = false; boolean nrhn = false; boolean sniff = false; boolean icl = false; String clustername = "elasticsearch"; String file = null; String type = null; boolean retrieve = false; String ksAlias = null; String tsAlias = null; String[] enabledProtocols = new String[0]; String[] enabledCiphers = new String[0]; Integer updateSettings = null; String index = ConfigConstants.SG_DEFAULT_CONFIG_INDEX; Boolean replicaAutoExpand = null; boolean reload = false; boolean failFast = false; boolean diagnose = false; boolean deleteConfigIndex = false; boolean enableShardAllocation = false; boolean acceptRedCluster = false; CommandLineParser parser = new DefaultParser(); try { CommandLine line = parser.parse( options, args ); hostname = line.getOptionValue("h", hostname); port = Integer.parseInt(line.getOptionValue("p", String.valueOf(port))); kspass = line.getOptionValue("kspass", kspass); //TODO null? //when no passwd is set tspass = line.getOptionValue("tspass", tspass); //TODO null? //when no passwd is set cd = line.getOptionValue("cd", cd); if(!cd.endsWith(File.separator)) { cd += File.separator; } ks = line.getOptionValue("ks"); ts = line.getOptionValue("ts"); kst = line.getOptionValue("kst", kst); tst = line.getOptionValue("tst", tst); nhnv = line.hasOption("nhnv"); nrhn = line.hasOption("nrhn"); clustername = line.getOptionValue("cn", clustername); sniff = line.hasOption("sniff"); icl = line.hasOption("icl"); file = line.getOptionValue("f", file); type = line.getOptionValue("t", type); retrieve = line.hasOption("r"); ksAlias = line.getOptionValue("ksalias", ksAlias); tsAlias = line.getOptionValue("tsalias", tsAlias); index = line.getOptionValue("i", index); String enabledCiphersString = line.getOptionValue("ec", null); String enabledProtocolsString = line.getOptionValue("ep", null); if(enabledCiphersString != null) { enabledCiphers = enabledCiphersString.split(","); } if(enabledProtocolsString != null) { enabledProtocols = enabledProtocolsString.split(","); } updateSettings = line.hasOption("us")?Integer.parseInt(line.getOptionValue("us")):null; reload = line.hasOption("rl"); if(line.hasOption("era")) { replicaAutoExpand = true; } if(line.hasOption("dra")) { replicaAutoExpand = false; } failFast = line.hasOption("ff"); diagnose = line.hasOption("dg"); deleteConfigIndex = line.hasOption("dci"); enableShardAllocation = line.hasOption("esa"); acceptRedCluster = line.hasOption("arc"); } catch( ParseException exp ) { System.err.println("ERR: Parsing failed. Reason: " + exp.getMessage()); formatter.printHelp("sgadmin.sh", options, true); return; } if(port < 9300) { System.out.println("WARNING: Seems you want connect to the a HTTP port."+System.lineSeparator() + " sgadmin connect through the transport port which is normally 9300."); } System.out.print("Will connect to "+hostname+":"+port); Socket socket = new Socket(); try { socket.connect(new InetSocketAddress(hostname, port)); } catch (java.net.ConnectException ex) { System.out.println(); System.out.println("ERR: Seems there is no elasticsearch running on "+hostname+":"+port+" - Will exit"); System.exit(-1); } finally { try { socket.close(); } catch (Exception e) { //ignore } } System.out.println(" ... done"); final Settings.Builder settingsBuilder = Settings .builder() .put("path.home", ".") .put("path.conf", ".") .put(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_KEYSTORE_FILEPATH, ks) .put(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_TRUSTSTORE_FILEPATH, ts) .put(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_KEYSTORE_PASSWORD, kspass) .put(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_TRUSTSTORE_PASSWORD, tspass) .put(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION, !nhnv) .put(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_ENFORCE_HOSTNAME_VERIFICATION_RESOLVE_HOST_NAME, !nrhn) .put(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_ENABLED, true) .put(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_KEYSTORE_TYPE, kst==null?(ks.endsWith(".jks")?"JKS":"PKCS12"):kst) .put(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_TRUSTSTORE_TYPE, tst==null?(ts.endsWith(".jks")?"JKS":"PKCS12"):tst) .putArray(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_ENABLED_CIPHERS, enabledCiphers) .putArray(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_ENABLED_PROTOCOLS, enabledProtocols) .put("cluster.name", clustername) .put("client.transport.ignore_cluster_name", icl) .put("client.transport.sniff", sniff); if(ksAlias != null) { settingsBuilder.put(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_KEYSTORE_ALIAS, ksAlias); } if(tsAlias != null) { settingsBuilder.put(SSLConfigConstants.SEARCHGUARD_SSL_TRANSPORT_TRUSTSTORE_ALIAS, tsAlias); } Settings settings = settingsBuilder.build(); try (TransportClient tc = TransportClient.builder().settings(settings).addPlugin(SearchGuardSSLPlugin.class) .addPlugin(SearchGuardPlugin.class) //needed for config update action only .build() .addTransportAddress(new InetSocketTransportAddress(new InetSocketAddress(hostname, port)))) { if(updateSettings != null) { Settings indexSettings = Settings.builder().put("index.number_of_replicas", updateSettings).build(); tc.execute(ConfigUpdateAction.INSTANCE, new ConfigUpdateRequest(new String[]{"config","roles","rolesmapping","internalusers","actiongroups"})).actionGet(); final UpdateSettingsResponse response = tc.admin().indices().updateSettings((new UpdateSettingsRequest(index).settings(indexSettings))).actionGet(); System.out.println("Reload config on all nodes"); System.out.println("Update number of replicas to "+(updateSettings) +" with result: "+response.isAcknowledged()); System.exit(response.isAcknowledged()?0:-1); } if(reload) { tc.execute(ConfigUpdateAction.INSTANCE, new ConfigUpdateRequest(new String[]{"config","roles","rolesmapping","internalusers","actiongroups"})).actionGet(); System.out.println("Reload config on all nodes"); System.exit(0); } if(replicaAutoExpand != null) { Settings indexSettings = Settings.builder() .put("index.auto_expand_replicas", replicaAutoExpand?"0-all":"false") .build(); tc.execute(ConfigUpdateAction.INSTANCE, new ConfigUpdateRequest(new String[]{"config","roles","rolesmapping","internalusers","actiongroups"})).actionGet(); final UpdateSettingsResponse response = tc.admin().indices().updateSettings((new UpdateSettingsRequest(index).settings(indexSettings))).actionGet(); System.out.println("Reload config on all nodes"); System.out.println("Auto-expand replicas "+(replicaAutoExpand?"enabled":"disabled")); System.exit(response.isAcknowledged()?0:-1); } if(enableShardAllocation) { final boolean successful = tc.admin().cluster() .updateSettings(new ClusterUpdateSettingsRequest() .transientSettings(ENABLE_ALL_ALLOCATIONS_SETTINGS) .persistentSettings(ENABLE_ALL_ALLOCATIONS_SETTINGS)) .actionGet() .isAcknowledged(); if(successful) { System.out.println("Persistent and transient shard allocation enabled"); } else { System.out.println("ERR: Unable to enable shard allocation"); } System.exit(successful?0:-1); } if(failFast) { System.out.println("Failfast is activated"); } if(diagnose) { generateDiagnoseTrace(tc); } System.out.println("Contacting elasticsearch cluster '"+clustername+"'"+(acceptRedCluster?"":" and wait for YELLOW clusterstate")+" ..."); ClusterHealthResponse chr = null; while(chr == null) { try { final ClusterHealthRequest chrequest = new ClusterHealthRequest().timeout(TimeValue.timeValueMinutes(5)); if(!acceptRedCluster) { chrequest.waitForYellowStatus(); } chr = tc.admin().cluster().health(chrequest).actionGet(); } catch (Exception e) { if(!failFast) { System.out.println("Cannot retrieve cluster state due to: "+e.getMessage()+". This is not an error, will keep on trying ..."); System.out.println(" * Try running sgadmin.sh with -icl and -nhnv (If thats works you need to check your clustername as well as hostnames in your SSL certificates)"); System.out.println(" * If this is not working, try running sgadmin.sh with --diagnose and see diagnose trace log file)"); System.out.println(" * Add --accept-red-cluster to allow sgadmin to operate on a red cluster."); } else { System.out.println("ERR: Cannot retrieve cluster state due to: "+e.getMessage()+"."); System.out.println(" * Try running sgadmin.sh with -icl and -nhnv (If thats works you need to check your clustername as well as hostnames in your SSL certificates)"); System.out.println(" * If this is not working, try running sgadmin.sh with --diagnose and see diagnose trace log file)"); System.out.println(" * Add --accept-red-cluster to allow sgadmin to operate on a red cluster."); System.exit(-1); } Thread.sleep(3000); continue; } } final boolean timedOut = chr.isTimedOut(); if (!acceptRedCluster && timedOut) { System.out.println("ERR: Timed out while waiting for a green or yellow cluster state."); System.out.println(" * Try running sgadmin.sh with -icl and -nhnv (If thats works you need to check your clustername as well as hostnames in your SSL certificates)"); System.out.println(" * If this is not working, try running sgadmin.sh with --diagnose and see diagnose trace log file)"); System.out.println(" * Add --accept-red-cluster to allow sgadmin to operate on a red cluster."); System.exit(-1); } System.out.println("Clustername: "+chr.getClusterName()); System.out.println("Clusterstate: "+chr.getStatus()); System.out.println("Number of nodes: "+chr.getNumberOfNodes()); System.out.println("Number of data nodes: "+chr.getNumberOfDataNodes()); final boolean indexExists = tc.admin().indices().exists(new IndicesExistsRequest(index)).actionGet().isExists(); final NodesInfoResponse nodesInfo = tc.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet(); if(deleteConfigIndex) { boolean success = true; if(indexExists) { success = tc.admin().indices().delete(new DeleteIndexRequest(index)).actionGet().isAcknowledged(); System.out.print("Deleted index '"+index+"'"); } else { System.out.print("No index '"+index+"' exists, so no need to delete it"); } System.exit(success?0:-1); } if (!indexExists) { System.out.print(index +" index does not exists, attempt to create it ... "); int replicas = chr.getNumberOfDataNodes()-1; final boolean indexCreated = tc.admin().indices().create(new CreateIndexRequest(index) // .mapping("config", source) // .settings(settings) //TODO "index.auto_expand_replicas", "0-all" .settings("index.number_of_shards", 1, "index.number_of_replicas", replicas) ).actionGet().isAcknowledged(); if (indexCreated) { System.out.println("done (with "+replicas+" replicas, auto expand replicas is off)"); } else { System.out.println("failed!"); System.out.println("FAIL: Unable to create the "+index+" index. See elasticsearch logs for more details"); System.exit(-1); } } else { System.out.println(index+" index already exists, so we do not need to create one."); try { ClusterHealthResponse chrsg = tc.admin().cluster().health(new ClusterHealthRequest(index)).actionGet(); if (chrsg.isTimedOut()) { System.out.println("ERR: Timed out while waiting for "+index+" index state."); } if (chrsg.getStatus() == ClusterHealthStatus.RED) { System.out.println("ERR: "+index+" index state is RED."); } if (chrsg.getStatus() == ClusterHealthStatus.YELLOW) { System.out.println("INFO: "+index+" index state is YELLOW, it seems you miss some replicas"); } } catch (Exception e) { if(!failFast) { System.out.println("Cannot retrieve "+index+" index state state due to "+e.getMessage()+". This is not an error, will keep on trying ..."); } else { System.out.println("ERR: Cannot retrieve "+index+" index state state due to "+e.getMessage()+"."); System.exit(-1); } } } if(retrieve) { String date = DATE_FORMAT.format(new Date()); boolean success = retrieveFile(tc, cd+"sg_config_"+date+".yml", index, "config"); success = success & retrieveFile(tc, cd+"sg_roles_"+date+".yml", index, "roles"); success = success & retrieveFile(tc, cd+"sg_roles_mapping_"+date+".yml", index, "rolesmapping"); success = success & retrieveFile(tc, cd+"sg_internal_users_"+date+".yml", index, "internalusers"); success = success & retrieveFile(tc, cd+"sg_action_groups_"+date+".yml", index, "actiongroups"); System.exit(success?0:-1); } boolean isCdAbs = new File(cd).isAbsolute(); System.out.println("Populate config from "+(isCdAbs?cd:new File(".", cd).getCanonicalPath())); if(file != null) { if(type == null) { System.out.println("ERR: type missing"); System.exit(-1); } if(!Arrays.asList(new String[]{"config", "roles", "rolesmapping", "internalusers","actiongroups" }).contains(type)) { System.out.println("ERR: Invalid type '"+type+"'"); System.exit(-1); } boolean success = uploadFile(tc, file, index, type); System.exit(success?0:-1); } boolean success = uploadFile(tc, cd+"sg_config.yml", index, "config"); success = success & uploadFile(tc, cd+"sg_roles.yml", index, "roles"); success = success & uploadFile(tc, cd+"sg_roles_mapping.yml", index, "rolesmapping"); success = success & uploadFile(tc, cd+"sg_internal_users.yml", index, "internalusers"); success = success & uploadFile(tc, cd+"sg_action_groups.yml", index, "actiongroups"); if(failFast && !success) { System.out.println("ERR: cannot upload configuration, see errors above"); System.exit(-1); } ConfigUpdateResponse cur = tc.execute(ConfigUpdateAction.INSTANCE, new ConfigUpdateRequest(new String[]{"config","roles","rolesmapping","internalusers","actiongroups"})).actionGet(); success = success & checkConfigUpdateResponse(cur, nodesInfo, 5); System.out.println("Done with "+(success?"success":"failures")); System.exit(success?0:-1); } // TODO audit changes to searchguard index } private static boolean checkConfigUpdateResponse(ConfigUpdateResponse response, NodesInfoResponse nir, int expectedConfigCount) { int expectedNodeCount = 0; for(NodeInfo ni: nir) { Settings nodeSettings = ni.getSettings(); //do not count tribe clients if(nodeSettings.get("tribe.name", null) == null) { expectedNodeCount++; } } boolean success = response.getNodes().length == expectedNodeCount; if(!success) { System.out.println("FAIL: Expected "+expectedNodeCount+" nodes to return response, but got only "+response.getNodes().length); } for(String nodeId: response.getNodesMap().keySet()) { ConfigUpdateResponse.Node node = (ConfigUpdateResponse.Node) response.getNodesMap().get(nodeId); boolean successNode = (node.getUpdatedConfigTypes() != null && node.getUpdatedConfigTypes().length == expectedConfigCount); if(!successNode) { System.out.println("FAIL: Expected "+expectedConfigCount+" config types for node "+nodeId+" but got only "+Arrays.toString(node.getUpdatedConfigTypes()) + " due to: "+node.getMessage()==null?"unknown reason":node.getMessage()); } success = success & successNode; } return success; } private static boolean uploadFile(Client tc, String filepath, String index, String type) { System.out.println("Will update '"+type+"' with "+filepath); try (Reader reader = new FileReader(filepath)) { final String id = tc .index(new IndexRequest(index).type(type).id("0").refresh(true) .consistencyLevel(WriteConsistencyLevel.DEFAULT).source(readXContent(reader, XContentType.YAML))) .actionGet().getId(); if ("0".equals(id)) { System.out.println(" SUCC: Configuration for '"+type+"' created or updated"); return true; } else { System.out.println(" FAIL: Configuration for '"+type+"' failed for unknown reasons. Pls. consult logfile of elasticsearch"); } } catch (Exception e) { System.out.println(" FAIL: Configuration for '"+type+"' failed because of "+e.toString()); } return false; } private static boolean retrieveFile(Client tc, String filepath, String index, String type) { System.out.println("Will retrieve '"+type+"' into "+filepath); try (Writer writer = new FileWriter(filepath)) { final GetResponse response = tc.get(new GetRequest(index).type(type).id("0").refresh(true).realtime(false)).actionGet(); if (response.isExists()) { if(response.isSourceEmpty()) { System.out.println(" FAIL: Configuration for '"+type+"' failed because of empty source"); return false; } String yaml = convertToYaml(response.getSourceAsBytesRef(), true); writer.write(yaml); System.out.println(" SUCC: Configuration for '"+type+"' stored in "+filepath); return true; } else { System.out.println(" FAIL: Get configuration for '"+type+"' because it does not exist"); } } catch (Exception e) { System.out.println(" FAIL: Get configuration for '"+type+"' failed because of "+e.toString()); } return false; } private static BytesReference readXContent(final Reader reader, final XContentType xContentType) throws IOException { BytesReference retVal; XContentParser parser = null; try { parser = XContentFactory.xContent(xContentType).createParser(reader); parser.nextToken(); final XContentBuilder builder = XContentFactory.jsonBuilder(); builder.copyCurrentStructure(parser); retVal = builder.bytes(); } finally { if (parser != null) { parser.close(); } } //validate Settings.builder().put(new JsonSettingsLoader().load(XContentHelper.createParser(retVal))).build(); return retVal; } private static String convertToYaml(BytesReference bytes, boolean prettyPrint) throws IOException { try (XContentParser parser = XContentFactory.xContent(XContentFactory.xContentType(bytes)).createParser(bytes.streamInput())) { parser.nextToken(); XContentBuilder builder = XContentFactory.yamlBuilder(); if (prettyPrint) { builder.prettyPrint(); } builder.copyCurrentStructure(parser); return builder.string(); } } protected static void generateDiagnoseTrace(final Client tc) { final String date = DATE_FORMAT.format(new Date()); final StringBuilder sb = new StringBuilder(); sb.append("Diagnostic sgadmin trace"+System.lineSeparator()); sb.append("ES client version: "+Version.CURRENT+System.lineSeparator()); sb.append("Client properties: "+System.getProperties()+System.lineSeparator()); sb.append(date+System.lineSeparator()); sb.append(System.lineSeparator()); try { sb.append("ClusterHealthRequest:"+System.lineSeparator()); ClusterHealthResponse nir = tc.admin().cluster().health(new ClusterHealthRequest()).actionGet(); sb.append(XContentHelper.toString(nir)); } catch (Exception e1) { sb.append(ExceptionsHelper.stackTrace(e1)); } try { sb.append(System.lineSeparator()+"NodesInfoResponse:"+System.lineSeparator()); NodesInfoResponse nir = tc.admin().cluster().nodesInfo(new NodesInfoRequest()).actionGet(); sb.append(XContentHelper.toString(nir)); } catch (Exception e1) { sb.append(ExceptionsHelper.stackTrace(e1)); } try { sb.append(System.lineSeparator()+"NodesStatsRequest:"+System.lineSeparator()); NodesStatsResponse nir = tc.admin().cluster().nodesStats(new NodesStatsRequest()).actionGet(); sb.append(XContentHelper.toString(nir)); } catch (Exception e1) { sb.append(ExceptionsHelper.stackTrace(e1)); } try { sb.append(System.lineSeparator()+"PendingClusterTasksRequest:"+System.lineSeparator()); PendingClusterTasksResponse nir = tc.admin().cluster().pendingClusterTasks(new PendingClusterTasksRequest()).actionGet(); sb.append(XContentHelper.toString(nir)); } catch (Exception e1) { sb.append(ExceptionsHelper.stackTrace(e1)); } try { sb.append(System.lineSeparator()+"ClusterStateRequest:"+System.lineSeparator()); ClusterStateResponse nir = tc.admin().cluster().state(new ClusterStateRequest()).actionGet(); sb.append(XContentHelper.toString(nir.getState())); } catch (Exception e1) { sb.append(ExceptionsHelper.stackTrace(e1)); } try { sb.append(System.lineSeparator()+"IndicesStatsRequest:"+System.lineSeparator()); IndicesStatsResponse nir = tc.admin().indices().stats(new IndicesStatsRequest()).actionGet(); sb.append(XContentHelper.toString(nir)); } catch (Exception e1) { sb.append(ExceptionsHelper.stackTrace(e1)); } try { File dfile = new File("sgadmin_diag_trace_"+date+".txt"); Files.write(sb,dfile,Charset.forName("UTF-8")); System.out.println("Diagnostic trace written to: "+dfile.getAbsolutePath()); } catch (Exception e1) { System.out.println("ERR: cannot write diag trace file due to "+e1); } } }