All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.quigley.zabbixj.agent.active.ActiveThread Maven / Gradle / Ivy
/*
* Copyright 2015 Michael Quigley
*
* 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.quigley.zabbixj.agent.active;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bouncycastle.crypto.tls.BasicTlsPSKIdentity;
import org.bouncycastle.crypto.tls.PSKTlsClient;
import org.bouncycastle.crypto.tls.TlsClientProtocol;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.quigley.zabbixj.ZabbixException;
import com.quigley.zabbixj.metrics.MetricsContainer;
public class ActiveThread extends Thread {
public ActiveThread(MetricsContainer metricsContainer, String hostName, InetAddress serverAddress, int serverPort, int refreshInterval, String pskIdentity, String psk) {
running = true;
checks = new HashMap>();
lastChecked = new HashMap();
this.metricsContainer = metricsContainer;
this.hostName = hostName;
this.serverAddress = serverAddress;
this.serverPort = serverPort;
this.refreshInterval = refreshInterval;
this.pskIdentity = pskIdentity;
this.psk = psk;
}
public void run() {
if(log.isDebugEnabled()) {
log.debug("ActiveThread Starting.");
}
try {
if(log.isDebugEnabled()) {
log.debug("Starting initial refresh of active checks.");
}
requestActiveChecks();
if(log.isDebugEnabled()) {
log.debug("Initial refresh of active checks completed.");
}
} catch(Exception e) {
log.error("Initial refresh failed.", e);
}
while(running) {
try {
Thread.sleep(1000);
} catch(InterruptedException ie) {
return;
}
long clock = System.currentTimeMillis() / 1000;
if((clock - lastRefresh) >= refreshInterval) {
try {
requestActiveChecks();
} catch(Exception e) {
log.error("Unable to refresh.", e);
}
}
for(int delay : checks.keySet()) {
long delayLastChecked = lastChecked.get(delay);
if(clock - delayLastChecked >= delay) {
try {
sendMetrics(delay, checks.get(delay));
} catch(Exception e) {
log.error("Unable to send metrics.", e);
}
}
}
}
}
private void requestActiveChecks() throws Exception {
if(log.isDebugEnabled()) {
log.debug("Requesting a list of active checks from the server.");
}
Socket socket = new Socket(serverAddress, serverPort);
InputStream input;
OutputStream output;
TlsClientProtocol protocol = null;
if (pskIdentity != null && psk != null) {
BasicTlsPSKIdentity basicIdentity = new BasicTlsPSKIdentity(pskIdentity.getBytes(), psk.getBytes());
PSKTlsClient tlsClient = new PSKTlsClient(basicIdentity);
SecureRandom secureRandom = new SecureRandom();
protocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(), secureRandom);
protocol.connect(tlsClient);
input = protocol.getInputStream();
output = protocol.getOutputStream();
} else {
input = socket.getInputStream();
output = socket.getOutputStream();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
JSONObject request = new JSONObject();
request.put("request", "active checks");
request.put("host", hostName);
byte[] buffer = getRequest(request);
output.write(buffer);
output.flush();
buffer = new byte[10240];
int read = 0;
while((read = input.read(buffer, 0, 10240)) != -1) {
baos.write(buffer, 0, read);
}
if (protocol != null ) {
protocol.close();
}
socket.close();
JSONObject response = getResponse(baos.toByteArray());
if(response.getString("response").equals("success")) {
refreshFromActiveChecksResponse(response);
} else {
log.warn("Server reported a failure when requesting active checks:" + response.getString("info"));
}
lastRefresh = System.currentTimeMillis() / 1000;
}
private void refreshFromActiveChecksResponse(JSONObject response) throws JSONException {
ActiveChecksResponseIndex index = getActiveChecksResponseIndex(response);
insertNewChecks(index);
pruneChangedChecks(index);
pruneUnusedDelays(index);
}
private ActiveChecksResponseIndex getActiveChecksResponseIndex(JSONObject response) throws JSONException {
ActiveChecksResponseIndex index = new ActiveChecksResponseIndex();
JSONArray data = response.getJSONArray("data");
for(int i = 0; i < data.length(); i++) {
JSONObject check = data.getJSONObject(i);
String key = check.getString("key");
int delay = check.getInt("delay");
index.add(key, delay);
}
return index;
}
private void insertNewChecks(ActiveChecksResponseIndex index) {
long clock = System.currentTimeMillis() / 1000;
for(String key : index.getIndex().keySet()) {
int delay = index.getIndex().get(key);
if(!checks.containsKey(delay)) {
if(log.isDebugEnabled()) {
log.debug("Inserting new check list for delay '" + delay + "'.");
}
checks.put(delay, new ArrayList());
}
List keysForDelay = checks.get(delay);
if(!keysForDelay.contains(key)) {
if(log.isDebugEnabled()) {
log.debug("Adding new key '" + key + "' to check list for delay '" + delay + "'.");
}
keysForDelay.add(key);
}
if(!lastChecked.containsKey(delay)) {
lastChecked.put(delay, clock);
}
}
}
private void pruneChangedChecks(ActiveChecksResponseIndex index) {
for(int delay : index.getDelays()) {
List keysForDelay = checks.get(delay);
for(String key : new ArrayList(keysForDelay)) {
if(index.getIndex().containsKey(key)) {
int currentDelay = index.getIndex().get(key);
if(currentDelay != delay) {
if(log.isDebugEnabled()) {
log.debug("Removing '" + key + "' from delay '" + delay + "' list.");
}
keysForDelay.remove(key);
}
} else {
if(log.isDebugEnabled()) {
log.debug("Removing '" + key + "' from delay '" + delay + "' list.");
}
keysForDelay.remove(key);
}
}
checks.put(delay, keysForDelay);
}
}
private void pruneUnusedDelays(ActiveChecksResponseIndex index) {
for(int delay : new ArrayList(lastChecked.keySet())) {
if(!index.getDelays().contains(delay)) {
if(log.isDebugEnabled()) {
log.debug("Removing unused delay '" + delay + "' from last checked list.");
}
lastChecked.remove(delay);
}
}
for(int delay : new ArrayList(checks.keySet())) {
if(!index.getDelays().contains(delay)) {
if(log.isDebugEnabled()) {
log.debug("Removing unused delay '" + delay + "' from checks.");
}
checks.remove(delay);
}
}
}
private void sendMetrics(int delay, List keyList) throws Exception {
if(log.isDebugEnabled()) {
String message = "Sending metrics for delay '" + delay + "' with keys: ";
for(int i = 0; i < keyList.size(); i++) {
if(i > 0) {
message += ", ";
}
message += keyList.get(i);
}
log.debug(message);
}
long clock = System.currentTimeMillis() / 1000;
JSONObject metrics = new JSONObject();
metrics.put("request", "agent data");
JSONArray data = new JSONArray();
for(String keyName : keyList) {
JSONObject key = new JSONObject();
key.put("host", hostName);
key.put("key", keyName);
try {
Object value = metricsContainer.getMetric(keyName);
key.put("value", value.toString());
} catch(Exception e) {
key.put("value", "ZBX_NOTSUPPORTED");
}
key.put("clock", "" + clock);
data.put(key);
}
metrics.put("data", data);
metrics.put("clock", "" + clock);
Socket socket = new Socket(serverAddress, serverPort);
InputStream input;
OutputStream output;
TlsClientProtocol protocol = null;
if (pskIdentity != null && psk != null) {
BasicTlsPSKIdentity basicIdentity = new BasicTlsPSKIdentity(pskIdentity.getBytes(), psk.getBytes());
PSKTlsClient tlsClient = new PSKTlsClient(basicIdentity);
SecureRandom secureRandom = new SecureRandom();
protocol = new TlsClientProtocol(socket.getInputStream(), socket.getOutputStream(), secureRandom);
protocol.connect(tlsClient);
input = protocol.getInputStream();
output = protocol.getOutputStream();
} else {
input = socket.getInputStream();
output = socket.getOutputStream();
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
output.write(getRequest(metrics));
output.flush();
byte[] buffer = new byte[10240];
int read = 0;
while((read = input.read(buffer, 0, 10240)) != -1) {
baos.write(buffer, 0, read);
}
if (protocol != null ) {
protocol.close();
}
socket.close();
JSONObject response = getResponse(baos.toByteArray());
if(response.getString("response").equals("success")) {
if(log.isDebugEnabled()) {
log.debug("The server reported success '" + response.getString("info") + "'.");
}
} else {
log.error("Failure!");
}
lastChecked.put(delay, clock);
}
private byte[] getRequest(JSONObject jsonObject) throws Exception {
byte[] requestBytes = jsonObject.toString().getBytes();
String header = "ZBXD\1";
byte[] headerBytes = header.getBytes();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
dos.writeLong(requestBytes.length);
dos.flush();
dos.close();
bos.close();
byte[] requestLengthBytes = bos.toByteArray();
byte[] allBytes = new byte[headerBytes.length + requestLengthBytes.length + requestBytes.length];
int index = 0;
for(int i = 0; i < headerBytes.length; i++) {
allBytes[index++] = headerBytes[i];
}
for(int i = 0; i < requestLengthBytes.length; i++) {
allBytes[index++] = requestLengthBytes[7 - i]; // Reverse the byte order.
}
for(int i = 0; i < requestBytes.length; i++) {
allBytes[index++] = requestBytes[i];
}
return allBytes;
}
private JSONObject getResponse(byte[] responseBytes) throws Exception {
byte[] sizeBuffer = new byte[8];
int index = 0;
for(int i = 12; i > 4; i--) {
sizeBuffer[index++] = responseBytes[i];
}
ByteArrayInputStream bais = new ByteArrayInputStream(sizeBuffer);
DataInputStream dis = new DataInputStream(bais);
long size = dis.readLong();
dis.close();
bais.close();
byte[] jsonBuffer = new byte[responseBytes.length - 13];
if(jsonBuffer.length != size) {
throw new ZabbixException("Reported and actual buffer sizes differ!");
}
index = 0;
for(int i = 13; i < responseBytes.length; i++) {
jsonBuffer[index++] = responseBytes[i];
}
JSONObject response = new JSONObject(new String(jsonBuffer));
return response;
}
public void shutdown() {
running = false;
}
private boolean running;
private Map> checks;
private Map lastChecked;
private long lastRefresh;
private MetricsContainer metricsContainer;
private String hostName;
private InetAddress serverAddress;
private int serverPort;
private int refreshInterval;
private String pskIdentity;
private String psk;
private class ActiveChecksResponseIndex {
public ActiveChecksResponseIndex() {
index = new HashMap();
delays = new ArrayList();
}
public Map getIndex() {
return index;
}
public List getDelays() {
return delays;
}
public void add(String key, int delay) {
index.put(key, delay);
if(!delays.contains(delay)) {
delays.add(delay);
}
}
private Map index;
private List delays;
}
private static Logger log = LoggerFactory.getLogger(ActiveThread.class);
}