/**
* Tencent is pleased to support the open source community by making MSEC available.
*
* Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
*
* Licensed under the GNU General Public 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
*
* https://opensource.org/licenses/GPL-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 beans.service;
import beans.dbaccess.ClusterInfo;
import beans.dbaccess.ServerInfo;
import beans.response.QueryESClusterDetailResponse;
import msec.org.DBUtil;
import org.apache.log4j.Logger;
import org.elasticsearch.ElasticsearchTimeoutException;
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.NodesInfoResponse;
import org.elasticsearch.action.admin.cluster.node.stats.NodeStats;
import org.elasticsearch.action.admin.cluster.node.stats.NodesStatsResponse;
import org.elasticsearch.action.admin.cluster.stats.ClusterStatsNodes;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateRequestBuilder;
import org.elasticsearch.action.admin.indices.template.put.PutIndexTemplateResponse;
import org.elasticsearch.client.transport.NoNodeAvailableException;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.cluster.health.ClusterHealthStatus;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.discovery.MasterNotDiscoveredException;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
import java.util.concurrent.TimeUnit;
public class ESHelper {
private static final String MAPPING = "{\n" +
" \"logs\" : {\n" +
" \"_all\" : { \"enabled\" : false },\n" +
" \"properties\" : {\n" +
" \"ClientIP\" : {\n" +
" \"type\" : \"string\",\n" +
" \"index\" : \"not_analyzed\"\n" +
" },\n" +
" \"IP\" : {\n" +
" \"type\" : \"string\",\n" +
" \"index\" : \"not_analyzed\"\n" +
" },\n" +
" \"ServerIP\" : {\n" +
" \"type\" : \"string\",\n" +
" \"index\" : \"not_analyzed\"\n" +
" },\n" +
" \"FileLine\" : {\n" +
" \"type\" : \"string\",\n" +
" \"index\" : \"not_analyzed\"\n" +
" },\n" +
" \"Level\" : {\n" +
" \"type\" : \"string\",\n" +
" \"index\" : \"not_analyzed\"\n" +
" },\n" +
" \"Caller\" : {\n" +
" \"type\" : \"string\",\n" +
" \"index\" : \"not_analyzed\"\n" +
" },\n" +
" \"ServiceName\" : {\n" +
" \"type\" : \"string\",\n" +
" \"index\" : \"not_analyzed\"\n" +
" },\n" +
" \"RPCName\" : {\n" +
" \"type\" : \"string\",\n" +
" \"index\" : \"not_analyzed\"\n" +
" },\n" +
" \"ReqID\" : {\n" +
" \"type\" : \"long\"\n" +
" },\n" +
" \"InsTime\" : {\n" +
" \"type\" : \"date\"\n" +
" },\n" +
" \"body\" : {\n" +
" \"type\" : \"string\",\n" +
" \"index\" : \"no\"\n" +
" }\n" +
" }\n" +
" }\n" +
" }";
public class ESHelperException extends RuntimeException {
public ESHelperException(String message) {
super(message);
}
public ESHelperException(Throwable e) {
super(e);
}
public ESHelperException(String message, Throwable cause) {
super(message, cause);
}
}
public ESHelper() {}
public ESHelper(ClusterInfo cluster_info_)
{
cluster_info = cluster_info_;
}
private void updateStatus(String ip, String status)
{
Logger logger = Logger.getLogger(InstallServerProc.class);
DBUtil util = new DBUtil();
if (util.getConnection() == null) {
return;
}
try {
String sql = "update t_install_plan set status=? where plan_id=? and ip=?";
List<Object> params = new ArrayList<Object>();
params.add(status);
params.add(cluster_info.getPlan_id());
params.add(ip);
int updNum = util.updateByPreparedStatement(sql, params);
if (updNum != 1) {
return;
}
} catch (Exception e) {
logger.error(e);
logger.error(e);
return;
} finally {
util.releaseConn();
}
}
private void updateStatus(String status)
{
Logger logger = Logger.getLogger(InstallServerProc.class);
DBUtil util = new DBUtil();
if (util.getConnection() == null) {
return;
}
try {
String sql = "update t_install_plan set status=? where plan_id=?";
List<Object> params = new ArrayList<Object>();
params.add(status);
params.add(cluster_info.getPlan_id());
int updNum = util.updateByPreparedStatement(sql, params);
if (updNum < 0) {
return;
}
} catch (Exception e) {
logger.error(e);
logger.error(e);
return;
} finally {
util.releaseConn();
}
}
private void updateStatus_waitforcluster(String status)
{
Logger logger = Logger.getLogger(InstallServerProc.class);
DBUtil util = new DBUtil();
if (util.getConnection() == null) {
return;
}
try {
String sql = "update t_install_plan set status=? where plan_id=? and status=?";
List<Object> params = new ArrayList<Object>();
params.add(status);
params.add(cluster_info.getPlan_id());
params.add(waitforcluster_message);
int updNum = util.updateByPreparedStatement(sql, params);
if (updNum < 0) {
return;
}
} catch (Exception e) {
logger.error(e);
logger.error(e);
return;
} finally {
util.releaseConn();
}
}
public void waitForClusterReady(final TransportClient client, ArrayList<String> ips, final ClusterHealthStatus status) throws IOException {
Logger logger = Logger.getLogger(ESHelper.class);
int timeout = 60;
int node_num = 0;
long begin = System.currentTimeMillis() / 1000L;
long end = begin;
Set<String> done_ips = new HashSet<>();
try {
logger.info("waiting for cluster state: " + status.name());
ClusterHealthResponse healthResponse = null;
while(true) {
try {
healthResponse = client.admin().cluster().prepareHealth().setWaitForStatus(status)
.setTimeout(TimeValue.timeValueSeconds(5)).execute().actionGet();
}
catch(NoNodeAvailableException | MasterNotDiscoveredException ex)
{
end = System.currentTimeMillis() / 1000L;
if(end-begin >= timeout)
throw new IOException("Server start timeout");
logger.info("server still starting/discovering, retry...");
try {
TimeUnit.SECONDS.sleep(2);
}
catch(InterruptedException e)
{
}
continue;
}
if (healthResponse != null && healthResponse.isTimedOut()) {
end = System.currentTimeMillis() / 1000L;
if(end-begin >= timeout) //timeout
throw new IOException("cluster not ready, current state is " + healthResponse.getStatus().name());
continue;
} else {
logger.info("cluster state ok");
int new_node_num = healthResponse.getNumberOfNodes();
if (new_node_num > node_num) {
node_num = new_node_num;
NodesInfoResponse nodeInfos = client.admin().cluster().prepareNodesInfo().all().get();
for (NodeInfo node : nodeInfos.getNodes()) {
if (!done_ips.contains(node.getHostname()) && ips.contains(node.getHostname())) {
updateStatus(node.getHostname(), "Done.");
done_ips.add(node.getHostname());
}
}
if(done_ips.size() == ips.size())
break;
end = System.currentTimeMillis() / 1000L;
if(end-begin >= timeout) //timeout
break;
}
}
}
} catch (final ElasticsearchTimeoutException e) {
throw new IOException("ES API timeout");
}
}
public void ClusterAdd(ArrayList<String> ips) {
Logger logger = Logger.getLogger(ESHelper.class);
TransportClient client = null;
try {
Settings settings = Settings.builder().put("cluster.name", cluster_info.getCluster_name()).put("client.transport.sniff", true).build();
for(String ip : ips) {
if(client == null) {
client = new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(ip), default_client_port));
}
else
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(ip), default_client_port));
}
updateStatus(waitforcluster_message);
waitForClusterReady(client, ips, ClusterHealthStatus.YELLOW);
}
catch(UnknownHostException e) {
logger.error(e);
updateStatus("[ERROR] Connect failed.");
}
catch(IOException e) {
logger.error(e);
updateStatus_waitforcluster("[ERROR] Joining cluster failed.");
}
finally {
if(client!=null)
client.close();
}
}
public void ClusterStatus(ArrayList<String> ips, String cluster_name, QueryESClusterDetailResponse response ) {
Logger logger = Logger.getLogger(ESHelper.class);
TransportClient client = null;
HashSet<String> total_ips = new HashSet<>(ips);
try {
Settings settings = Settings.builder().put("cluster.name", cluster_name).put("client.transport.sniff", true).build();
for(String ip : ips) {
if(client == null) {
client = new PreBuiltTransportClient(settings).addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(ip), default_client_port));
}
else
client.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(ip), default_client_port));
}
ClusterHealthResponse healthResponse = client.admin().cluster().prepareHealth().setTimeout(TimeValue.timeValueSeconds(5)).execute().actionGet();
if (healthResponse != null && !healthResponse.isTimedOut()) {
response.setActive_shards(healthResponse.getActiveShards());
response.setTotal_shards(healthResponse.getActiveShards()+healthResponse.getUnassignedShards());
response.setHealth_status(healthResponse.getStatus().toString().toLowerCase());
response.setServer_port(default_port);
logger.info(healthResponse);
if(healthResponse.getNumberOfNodes() > 0) {
NodesStatsResponse nodeStats = client.admin().cluster().prepareNodesStats().all().get();
if (nodeStats != null) {
for(NodeStats stats: nodeStats.getNodes()) {
QueryESClusterDetailResponse.RTInfo info = new QueryESClusterDetailResponse().new RTInfo();
info.setOK(true);
info.setAvail_disk_size(stats.getFs().getTotal().getAvailable().getBytes());
info.setDoc_count(stats.getIndices().getDocs().getCount());
info.setDoc_disk_size(stats.getIndices().getStore().getSizeInBytes());
response.getInfo_map().put(stats.getNode().getAddress().getHost(), info);
total_ips.add(stats.getNode().getAddress().getHost());
}
}
}
}
//update Zen settings
client.admin().cluster().prepareUpdateSettings()
.setPersistentSettings(Settings.builder().put("discovery.zen.minimum_master_nodes", total_ips.size()/2+1))
.setTransientSettings(Settings.builder().put("discovery.zen.minimum_master_nodes", total_ips.size()/2+1))
.get();
//update template settings
PutIndexTemplateResponse tpl_resp = client.admin().indices().preparePutTemplate("template_msec")
.setTemplate("msec_*")
.setSettings(
Settings.builder()
.put("number_of_replicas", 1)
.put("refresh_interval", "30s")
)
.addMapping("logs", MAPPING)
.execute()
.get();
logger.info("Create mapping: " + tpl_resp.isAcknowledged());
}
catch(UnknownHostException e) {
logger.error(e);
}
catch(Exception e) {
logger.error(e);
}
finally {
if(client!=null)
client.close();
}
}
public void RemoveSet(ArrayList<String> ips) {
}
ClusterInfo cluster_info;
final static String waitforcluster_message = "(4/5) Waiting for cluster ready";
final static public int default_port = 9200;
final static public int default_client_port = 9300;
}