Java tutorial
/* * Copyright (c) 2015-2016 Fraunhofer FOKUS * 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 org.openbaton.monitoring.agent; import com.google.gson.*; import com.mashape.unirest.http.HttpMethod; import com.mashape.unirest.http.HttpResponse; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import java.io.*; import java.net.InetSocketAddress; import java.rmi.RemoteException; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.openbaton.catalogue.mano.common.faultmanagement.VirtualizedResourceAlarmNotification; import org.openbaton.catalogue.mano.common.faultmanagement.VirtualizedResourceAlarmStateChangedNotification; import org.openbaton.catalogue.mano.common.monitoring.*; import org.openbaton.catalogue.nfvo.EndpointType; import org.openbaton.catalogue.nfvo.Item; import org.openbaton.catalogue.util.IdGenerator; import org.openbaton.exceptions.BadFormatException; import org.openbaton.exceptions.MonitoringException; import org.openbaton.monitoring.agent.alarm.catalogue.Metric; import org.openbaton.monitoring.agent.performance.management.catalogue.PmJob; import org.openbaton.monitoring.agent.performance.management.catalogue.Threshold; import org.openbaton.monitoring.agent.zabbix.api.ZabbixApiManager; import org.openbaton.monitoring.interfaces.MonitoringPlugin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** Created by mob on 22.10.15. */ public class ZabbixMonitoringAgent extends MonitoringPlugin { private static Logger logger = LoggerFactory.getLogger(ZabbixMonitoringAgent.class); private int historyLength; private int requestFrequency; private String zabbixPluginIp; private ZabbixSender zabbixSender; private ZabbixApiManager zabbixApiManager; private String notificationReceiverServerContext; private int notificationReceiverServerPort; private Gson mapper; private Random random = new Random(); private Logger log = LoggerFactory.getLogger(this.getClass()); private List<AlarmEndpoint> subscriptions; private Map<String, PmJob> pmJobs; private Map<String, Threshold> thresholds; private Map<String, List<Alarm>> datacenterAlarms; private String type; private Map<String, List<String>> triggerIdHostnames; private Map<String, String> triggerIdActionIdMap; private LimitedQueue<State> history; private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); //Server properties private HttpServer server; private MyHandler myHandler; // private Runnable updateHistory = new Runnable() { @Override public void run() { JsonObject responseObj; String params = "{'output': ['name'], 'selectItems': ['key_', 'lastvalue' ,'units']}"; try { responseObj = callPost(params, "host.get"); } catch (MonitoringException e) { log.error("Exception while updating hosts:" + e.getMessage()); return; } long timestamp = System.currentTimeMillis() / 1000; JsonArray hostArray = responseObj.get("result").getAsJsonArray(); Iterator<JsonElement> iterator = hostArray.iterator(); // String is the hostname Map<String, HistoryObject> snapshot = new HashMap<String, HistoryObject>(); while (iterator.hasNext()) { JsonObject jsonObj = iterator.next().getAsJsonObject(); String hostName = jsonObj.getAsJsonObject().get("name").getAsString(); JsonArray itemArray = jsonObj.get("items").getAsJsonArray(); Iterator<JsonElement> itemIterator = itemArray.iterator(); HistoryObject ho = new HistoryObject(); ho.setHostId(jsonObj.get("hostid").getAsString()); // add the values to the HistoryObject while (itemIterator.hasNext()) { JsonObject item = itemIterator.next().getAsJsonObject(); ho.setUnit(item.get("key_").getAsString(), item.get("units").getAsString()); ho.setMeasurement(item.get("key_").getAsString(), item.get("lastvalue").getAsString()); } snapshot.put(hostName, ho); } State state = new State(timestamp, snapshot); synchronized (history) { history.add(state); } } }; private JsonObject callPost(String params, String method) throws MonitoringException { JsonObject responseObj; responseObj = zabbixSender.callPost(params, method); return responseObj; } public ZabbixMonitoringAgent() throws RemoteException, MonitoringException { super(); init(); try { launchServer(notificationReceiverServerPort, notificationReceiverServerContext); } catch (IOException e) { throw new RemoteException(e.getMessage(), e); } } /** * @param hostnames a list of hostnames * @param metrics a list of the metrics that shall be retrieved from every hostname * @param period you get for every suitable metric the average value it had for the last <period> * seconds of time * @return a list of Items * @throws RemoteException * <p>The method gives back a list of Items. For every combination of hostname and metric, one * ZabbixItem will be in the list. Every ZabbixItem contains the hostname, the host id, the * latest value of one metric and the average value of the metric in the last <period> * seconds. The average value is in the field 'value', the latest value is in the field * 'lastValue'. The ZabbixItem's id is always null and the version 0. */ //@Override public List<Item> getMeasurementResults(List<String> hostnames, List<String> metrics, String period) throws MonitoringException { log.info("Looking for items for hostnames: " + hostnames.toString()); List<Item> items = new LinkedList<>(); long currTime = System.currentTimeMillis() / 1000; long startingTime = currTime - Long.parseLong(period); // that's the point of time where requested history starts synchronized (history) { LinkedList<State> historyImportant = new LinkedList<>(); // the part of the history which lies in the period Iterator<State> iterator = history.descendingIterator(); // get the latest history entry if (iterator.hasNext()) { State entry = iterator.next(); historyImportant.add(entry); // check if the period is too long if (!iterator.hasNext() && entry.getTime() > startingTime) throw new MonitoringException("The period is too long for the existing history."); } while (iterator.hasNext()) { State entry = iterator.next(); if (entry.getTime() < startingTime) { break; } historyImportant.add(entry); if (!iterator.hasNext() && entry.getTime() > startingTime) { if (!Boolean.parseBoolean(properties.getProperty("enable-exception", "false"))) return items; else throw new MonitoringException("The period is too long for the existing history."); } } log.debug("Calculated History is: " + historyImportant.toString()); for (String host : hostnames) { // check if the host exists in the latest state of history if (!historyImportant.peekFirst().getHostsHistory().containsKey(host)) if (Boolean.parseBoolean(properties.getProperty("enable-exception", "false"))) throw new MonitoringException("The hostname " + host + " does not exist."); for (String metric : metrics) { Iterator<State> historyIterator = historyImportant.iterator(); // Check for wildcards if (metric.contains("*")) { log.debug("Querying Wildcard metric!"); Iterator<State> wildcardHistoryIterator = historyImportant.iterator(); Map<String, HistoryObject> wildcardHostsAndHistory = wildcardHistoryIterator.next() .getHostsHistory(); if (!wildcardHostsAndHistory.containsKey(host)) { if (!Boolean.parseBoolean(properties.getProperty("enable-exception", "false"))) { log.warn("The period is too long for host " + host + " because he just started existing inside the specified time frame."); continue; } else throw new MonitoringException("The period is too long for host " + host + " because he just started existing inside the specified time frame."); } LinkedList<String> wildcardMetrics = wildcardHostsAndHistory.get(host) .getWildcardKeys(metric); //log.debug("Found wildcard metrics : " + wildcardMetrics); for (String calculatedMetric : wildcardMetrics) { Item calculatedWildcardItem = new Item(); //log.debug("Setting : host :" + host + " , metric : " + calculatedMetric); calculatedWildcardItem.setHostname(host); calculatedWildcardItem.setMetric(calculatedMetric); //log.debug("Checking the host history"); Map<String, HistoryObject> hostsHistory = historyImportant .get(historyImportant.size() - 1).getHostsHistory(); //log.debug("Checking specific host history"); HistoryObject hObj = hostsHistory.get(host); //log.debug("Setting host id : " + hObj.getHostId()); calculatedWildcardItem.setHostId(hObj.getHostId()); //log.debug("Setting metric : " + calculatedMetric); String value = hObj.getMeasurement(calculatedMetric); calculatedWildcardItem.setLastValue("" + Double.parseDouble(value)); HashMap<String, String> metadata = new HashMap<>(); metadata.put(calculatedMetric, hObj.getUnit(calculatedMetric)); if (calculatedWildcardItem.getMetadata() == null) { calculatedWildcardItem.setMetadata(metadata); } else { HashMap<String, String> fusedmetadata = new HashMap<>(); fusedmetadata.putAll(metadata); fusedmetadata.putAll(calculatedWildcardItem.getMetadata()); calculatedWildcardItem.setMetadata(fusedmetadata); } /* Double avg = Double.valueOf(0); if (avg != null) { // it is a number and no string int tot = 0; Double parseDouble = Double.parseDouble(wildcardHostsAndHistory.get(host).getMeasurement(calculatedMetric)); log.debug("HistoryValue is: " + parseDouble); avg += parseDouble; tot++; } log.debug(avg + " / " + tot + " = " + (avg / tot)); avg /= tot; log.debug("Value found is: " + avg); */ log.debug("Adding item: " + calculatedWildcardItem); items.add(calculatedWildcardItem); } } else { Item item = new Item(); item.setHostname(host); item.setMetric(metric); Map<String, HistoryObject> hostsHistory = historyImportant.get(historyImportant.size() - 1) .getHostsHistory(); log.debug("All hosts are: " + hostsHistory.keySet()); if (!hostsHistory.keySet().contains(host)) { log.warn("Host " + host + " is not contained in the history"); break; } HistoryObject hObj = hostsHistory.get(host); log.debug("HistoryObject is: " + hObj); if (!hObj.keyExists(metric)) if (!Boolean.parseBoolean(properties.getProperty("enable-exception", "false"))) { log.warn("The metric " + metric + " does not exist for host " + host + "."); continue; } else throw new MonitoringException( "The metric " + metric + " does not exist for host " + host + "."); item.setHostId(hObj.getHostId()); String value = hObj.getMeasurement(metric); item.setLastValue("" + Double.parseDouble(value)); HashMap<String, String> metadata = new HashMap<>(); metadata.put(metric, hObj.getUnit(metric)); if (item.getMetadata() == null) { item.setMetadata(metadata); } else { HashMap<String, String> fusedmetadata = new HashMap<>(); fusedmetadata.putAll(metadata); fusedmetadata.putAll(item.getMetadata()); item.setMetadata(fusedmetadata); } Double avg = Double.valueOf(0); if (avg != null) { // it is a number and no string int tot = 0; while (historyIterator.hasNext()) { Map<String, HistoryObject> hostsAndHistory = historyIterator.next() .getHostsHistory(); if (!hostsAndHistory.containsKey(host)) { if (!Boolean .parseBoolean(properties.getProperty("enable-exception", "false"))) { log.warn("The period is too long for host " + host + " because he just started existing inside the specified time frame."); continue; } else throw new MonitoringException("The period is too long for host " + host + " because he just started existing inside the specified time frame."); } if (!hostsAndHistory.get(host).keyExists(metric)) { if (!Boolean .parseBoolean(properties.getProperty("enable-exception", "false"))) { log.warn("The metric " + metric + "did not exist at every time in the specified period for host " + host + "."); continue; } else throw new MonitoringException("The metric " + metric + "did not exist at every time in the specified period for host " + host + "."); } Double parseDouble = Double .parseDouble(hostsAndHistory.get(host).getMeasurement(metric)); log.debug("HistoryValue is: " + parseDouble); avg += parseDouble; tot++; } log.debug(avg + " / " + tot + " = " + (avg / tot)); avg /= tot; log.debug("Value found is: " + avg); } // if the metric's value is a String, just store the last value as value item.setValue("" + avg); log.debug("Adding item: " + item); items.add(item); } } } } return items; } private void init() throws RemoteException, MonitoringException { loadProperties(); String zabbixHost = properties.getProperty("zabbix-host"); String zabbixPort = properties.getProperty("zabbix-port"); String username = properties.getProperty("user-zbx"); String password = properties.getProperty("password-zbx"); String zabbixServerVersion = properties.getProperty("zabbix-server-version", "3.0"); zabbixPluginIp = properties.getProperty("zabbix-plugin-ip"); Boolean zabbixSsl = Boolean.parseBoolean(properties.getProperty("zabbix-ssl", "false")); String zabbixEndpoint = properties.getProperty("zabbix-endpoint", "/zabbix/api_jsonrpc.php"); zabbixSender = new ZabbixSender(zabbixHost, zabbixPort, zabbixEndpoint, zabbixSsl, username, password); zabbixSender.authenticate(); zabbixApiManager = new ZabbixApiManager(zabbixSender, zabbixServerVersion); String nrsp = properties.getProperty("notification-receiver-server-port", "8010"); notificationReceiverServerPort = Integer.parseInt(nrsp); notificationReceiverServerContext = properties.getProperty("notification-receiver-server-context", "/zabbixplugin/notifications"); type = properties.getProperty("type"); requestFrequency = Integer.parseInt(properties.getProperty("client-request-frequency")); historyLength = Integer.parseInt(properties.getProperty("history-length")); history = new LimitedQueue<>(historyLength); mapper = new GsonBuilder().setPrettyPrinting().create(); subscriptions = new ArrayList<>(); String faultsConsumerEndpoint = properties.getProperty("faults-consumer-endpoint"); subscribeForFault(new AlarmEndpoint("faults-consumer", null, EndpointType.REST, faultsConsumerEndpoint, PerceivedSeverity.MINOR)); triggerIdHostnames = new HashMap<>(); pmJobs = new HashMap<>(); thresholds = new HashMap<>(); triggerIdActionIdMap = new HashMap<>(); if (requestFrequency > 0) { updateHistory.run(); scheduler.scheduleAtFixedRate(updateHistory, 3, requestFrequency, TimeUnit.SECONDS); } datacenterAlarms = new HashMap<>(); } /** terminate the scheduler safely */ public void terminate() { log.info("Shuting down..."); shutdownAndAwaitTermination(scheduler); server.stop(10); zabbixSender.destroy(); } void shutdownAndAwaitTermination(ExecutorService pool) { pool.shutdown(); // Disable new tasks from being submitted try { // Wait a while for existing tasks to terminate if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { pool.shutdownNow(); // Cancel currently executing tasks // Wait a while for tasks to respond to being cancelled if (!pool.awaitTermination(60, TimeUnit.SECONDS)) System.err.println("Pool did not terminate"); } } catch (InterruptedException ie) { // (Re-)Cancel if current thread also interrupted pool.shutdownNow(); // Preserve interrupt status Thread.currentThread().interrupt(); } } private void handleNotification(ZabbixNotification zabbixNotification) { List<AlarmEndpoint> subscribers = getSubscribers(zabbixNotification); if (subscribers.isEmpty()) { log.debug("No subscribers for this notification"); return; } log.debug("subscribers: " + subscribers); //Check if the trigger is crossed for the first time boolean isNewNotification = isNewNotification(zabbixNotification); if (isNewNotification && zabbixNotification.getTriggerStatus().ordinal() == TriggerStatus.PROBLEM.ordinal()) { //TODO create Threshold crossed notification log.debug("Yes is new"); //if the severity of the notification is more than Not classified or Information, // create an alarm or change the state of an existing alarm if (!(zabbixNotification.getTriggerSeverity().equals("Not classified") || zabbixNotification.getTriggerSeverity().equals("Information"))) { log.debug("creating alarm"); VRAlarm vrAlarm = createAlarm(zabbixNotification); AbstractVirtualizedResourceAlarm notification = new VirtualizedResourceAlarmNotification( vrAlarm.getThresholdId(), vrAlarm); log.debug("Sending alarm:" + vrAlarm); sendFaultNotification(notification, subscribers); } List<String> hostnames = new ArrayList<>(); hostnames.add(zabbixNotification.getHostName()); triggerIdHostnames.put(zabbixNotification.getTriggerId(), hostnames); log.debug("triggerIdHostnames: " + triggerIdHostnames); } else if (!isNewNotification) { //TODO create Threshold crossed notification if (!(zabbixNotification.getTriggerSeverity().equals("Not classified") || zabbixNotification.getTriggerSeverity().equals("Information"))) { AlarmState alarmState = zabbixNotification.getTriggerStatus() == TriggerStatus.OK ? AlarmState.CLEARED : AlarmState.UPDATED; AbstractVirtualizedResourceAlarm notification = new VirtualizedResourceAlarmStateChangedNotification( zabbixNotification.getTriggerId(), alarmState); sendFaultNotification(notification, subscribers); } } } private boolean isNewNotification(ZabbixNotification zabbixNotification) { if (triggerIdHostnames.get(zabbixNotification.getTriggerId()) == null) return true; if (!(triggerIdHostnames.get(zabbixNotification.getTriggerId()).contains(zabbixNotification.getHostName()))) return true; return false; } private void sendFaultNotification(AbstractVirtualizedResourceAlarm notification, List<AlarmEndpoint> subscribers) { for (AlarmEndpoint ae : subscribers) { notifyFault(ae, notification); } } private List<AlarmEndpoint> getSubscribers(ZabbixNotification notification) { List<AlarmEndpoint> subscribersForNotification = new ArrayList<>(); PerceivedSeverity notificationPerceivedSeverity = getPerceivedSeverity(notification.getTriggerSeverity()); for (AlarmEndpoint ae : subscriptions) { if (notificationPerceivedSeverity.ordinal() >= ae.getPerceivedSeverity().ordinal()) { subscribersForNotification.add(ae); } } return subscribersForNotification; } private VRAlarm createAlarm(ZabbixNotification zabbixNotification) { VRAlarm vrAlarm = new VRAlarm(); vrAlarm.setThresholdId(zabbixNotification.getTriggerId()); //AlarmRaisedTime: It indicates the date and time when the alarm is first raised by the managed object. vrAlarm.setAlarmRaisedTime(zabbixNotification.getEventDate() + " " + zabbixNotification.getEventTime()); //EventTime: Time when the fault was observed. DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss"); Date date = new Date(); vrAlarm.setEventTime(dateFormat.format(date)); //AlarmState: State of the alarm, e.g. fired?, updated?, cleared?. vrAlarm.setAlarmState(AlarmState.FIRED); /* Type of the fault.The allowed values for the faultyType attribute depend on the type of the related managed object. For example, a resource of type compute? may have faults of type CPU failure?, memory failure?, network card failure?, etc. */ vrAlarm.setFaultType(getFaultType(zabbixNotification.getItemKey())); /* Identifier of the affected managed Object. The Managed Objects for this information element will be virtualised resources. These resources shall be known by the Virtualised Resource Management interface. */ //TODO handle a notification fired by a threshold on more than one hostname vrAlarm.setManagedObject(zabbixNotification.getHostName()); //Perceived severity of the managed object failure vrAlarm.setPerceivedSeverity(getPerceivedSeverity(zabbixNotification.getTriggerSeverity())); return vrAlarm; } private PerceivedSeverity getPerceivedSeverity(String triggerSeverity) { switch (triggerSeverity) { case "Not classified": return PerceivedSeverity.INDETERMINATE; case "Information": return PerceivedSeverity.WARNING; case "Warning": return PerceivedSeverity.WARNING; case "Average": return PerceivedSeverity.MINOR; case "High": return PerceivedSeverity.MAJOR; case "Disaster": return PerceivedSeverity.CRITICAL; } return null; } private Integer getPriority(PerceivedSeverity perceivedSeverity) { switch (perceivedSeverity) { case INDETERMINATE: return 0 /*Not classified*/; case WARNING: return 2 /*"Warning"*/; case MINOR: return 3 /*"Average"*/; case MAJOR: return 4 /*"High"*/; case CRITICAL: return 5 /*"Disaster"*/; } return null; } private FaultType getFaultType(String itemKey) { Metric metric; int index = itemKey.indexOf('['); if (index != -1) metric = getMetric(itemKey.substring(0, index)); else metric = getMetric(itemKey); switch (metric) { case SYSTEM_CPU_LOAD: return FaultType.COMPUTE_HOGS_CPU; case NET_TCP_LISTEN: return FaultType.IO_NETWORK_FRAME_TRANSMIT; } return null; } private Metric getMetric(String substring) { String metricString = substring.toUpperCase().replaceAll("\\.", "_"); Metric result = Metric.valueOf(metricString); log.debug("Obtained Metric: " + result + " from: " + substring); return result; } private void launchServer(int port, String context) throws IOException { server = HttpServer.create(new InetSocketAddress(port), 1); myHandler = new MyHandler(); server.createContext(context, myHandler); log.debug("Notification receiver server running on url: " + server.getAddress() + " port:" + server.getAddress().getPort()); server.setExecutor(null); server.start(); } @Override public String subscribeForFault(AlarmEndpoint endpoint) throws MonitoringException { String subscriptionId = IdGenerator.createId(); endpoint.setId(subscriptionId); subscriptions.add(endpoint); return subscriptionId; } @Override public String unsubscribeForFault(String alarmEndpointId) { Iterator<AlarmEndpoint> iterator = subscriptions.iterator(); while (iterator.hasNext()) { AlarmEndpoint currentAlarmEndpoint = iterator.next(); if (currentAlarmEndpoint.getId().equals(alarmEndpointId)) { iterator.remove(); return alarmEndpointId; } } return ""; } @Override public void notifyFault(AlarmEndpoint endpoint, AbstractVirtualizedResourceAlarm event) { HttpResponse<String> response = null; try { if (event instanceof VirtualizedResourceAlarmNotification) { VirtualizedResourceAlarmNotification vran = (VirtualizedResourceAlarmNotification) event; String jsonAlarm = mapper.toJson(vran, VirtualizedResourceAlarmNotification.class); log.debug("Sending VirtualizedResourceAlarmNotification: " + jsonAlarm + " to: " + endpoint.getEndpoint()); response = zabbixSender.doRestCallWithJson(endpoint.getEndpoint(), jsonAlarm, HttpMethod.POST, "application/json"); } else if (event instanceof VirtualizedResourceAlarmStateChangedNotification) { VirtualizedResourceAlarmStateChangedNotification vrascn = (VirtualizedResourceAlarmStateChangedNotification) event; String jsonAlarm = mapper.toJson(vrascn, VirtualizedResourceAlarmStateChangedNotification.class); log.debug("Sending VirtualizedResourceAlarmStateChangedNotification: " + jsonAlarm + " to: " + endpoint); response = zabbixSender.doRestCallWithJson(endpoint.getEndpoint(), jsonAlarm, HttpMethod.PUT, "application/json"); } log.debug("Response is:" + response.getBody()); } catch (Exception e) { if (log.isDebugEnabled()) log.error(e.getMessage(), e); else log.error(e.getMessage()); } } @Override public List<Alarm> getAlarmList(String vnfId, PerceivedSeverity perceivedSeverity) { return null; } @Override public String createPMJob(ObjectSelection objectSelection, List<String> performanceMetrics, List<String> performanceMetricGroup, Integer collectionPeriod, Integer reportingPeriod) throws MonitoringException { if (objectSelection == null || objectSelection.getObjectInstanceIds().isEmpty()) throw new MonitoringException("The objectSelection is null or empty"); if (performanceMetrics == null && performanceMetricGroup == null) throw new MonitoringException( "At least performanceMetrics or performanceMetricGroup need to be present"); if (collectionPeriod < 0 || reportingPeriod < 0) throw new MonitoringException("The collectionPeriod or reportingPeriod is negative"); PmJob pmJob = null; try { if (performanceMetrics == null || performanceMetrics.isEmpty()) throw new MonitoringException("PerformanceMetrics is null"); pmJob = new PmJob(objectSelection, collectionPeriod); for (String hostname : objectSelection.getObjectInstanceIds()) { String hostId = zabbixApiManager.getHostId(hostname); String interfaceId = zabbixApiManager.getHostInterfaceId(hostId); for (String performanceMetric : performanceMetrics) { log.debug("The performance metric is: " + performanceMetric); int type = getType(collectionPeriod); // Check for wildcard if (performanceMetric.contains("*")) { // Get the host list log.debug("The performance metric is a wildcard"); String params = "{'output': ['itemid','key_']," + "'hostids': '" + hostId + "' ,'search': {'key_':'" + performanceMetric + "' },'searchWildcardsEnabled': 'true' }"; String method = "item.get"; //log.debug(params); JsonObject items = callPost(params, method); //log.debug(items.toString()); JsonArray itemArray = items.get("result").getAsJsonArray(); Iterator<JsonElement> iterator = itemArray.iterator(); while (iterator.hasNext()) { JsonObject jsonObj = iterator.next().getAsJsonObject(); String itemId = jsonObj.getAsJsonObject().get("itemid").getAsString(); String key = jsonObj.getAsJsonObject().get("key_").getAsString(); if (itemId != null) { //log.debug(itemId + " : " + key); pmJob.addPerformanceMetric(itemId, key); } } } else { // check already exists String itemId = zabbixApiManager.getItemId(performanceMetric, hostId); if (itemId != null) { pmJob.addPerformanceMetric(itemId, performanceMetric); continue; } //Check if is present a LLD if (isPrototype(performanceMetric)) { String ruleId = zabbixApiManager.getRuleId(hostId); itemId = zabbixApiManager.createPrototypeItem(collectionPeriod, hostId, interfaceId, performanceMetric, "ZabbixPrototypeItem on demand: " + performanceMetric, type, 0, ruleId); pmJob.addPerformanceMetric(itemId, performanceMetric); } else { itemId = zabbixApiManager.createItem("ZabbixItem on demand: " + performanceMetric, collectionPeriod, hostId, type, 0, performanceMetric, interfaceId); pmJob.addPerformanceMetric(itemId, performanceMetric); } } } } } catch (Exception e) { log.error(e.getMessage(), e); throw new MonitoringException("The Pm job cannot be created: " + e.getMessage(), e); } pmJobs.put(pmJob.getPmjobId(), pmJob); return pmJob.getPmjobId(); } // The type of the item can be Zabbix agent or Zabbix agent (active) // Zabbix agent = 0 // Zabbix agent (active) = 7 // If the update interval of the item (collection period) is less or equals to 10 seconds than we create a // Zabbix agent (active) item which is typically faster private int getType(Integer collectionPeriod) { if (collectionPeriod <= 10) return 7; return 0; } @Override public List<String> deletePMJob(List<String> pmJobIdsToDelete) throws MonitoringException { if (pmJobIdsToDelete == null) throw new MonitoringException("The list of pmJob ids is null"); if (pmJobIdsToDelete.isEmpty()) throw new MonitoringException("The list of pmJob is empty"); List<String> deletedPmJobId = new ArrayList<>(); try { log.debug("TO delete: " + pmJobIdsToDelete); for (String pmJobId : pmJobIdsToDelete) { PmJob pmJob = pmJobs.get(pmJobId); log.debug("Current PM job: " + pmJob); if (pmJob != null) { List<String> itemIds = new ArrayList<>(); List<String> prototypeItemIds = new ArrayList<>(); //Map<String,String> performanceMetrics = pmJob.getPerformanceMetrics(); for (Map.Entry<String, String> entry : pmJob.getPerformanceMetrics().entrySet()) { if (isPrototype(entry.getValue())) prototypeItemIds.add(entry.getKey()); else itemIds.add(entry.getKey()); } if (!itemIds.isEmpty()) zabbixApiManager.deleteItems(itemIds); if (!prototypeItemIds.isEmpty()) zabbixApiManager.deletePrototypeItems(prototypeItemIds); deletedPmJobId.add(pmJobId); } } log.debug("Deleted pmjobs: " + pmJobIdsToDelete); } catch (Exception e) { throw new MonitoringException("The Pm job cannot be deleted: " + e.getMessage(), e); } return deletedPmJobId; } @Override public List<Item> queryPMJob(List<String> hostnames, List<String> metrics, String period) throws MonitoringException { return getMeasurementResults(hostnames, metrics, period); } @Override public void subscribe() { } @Override public void notifyInfo() { } @Override public String createThreshold(ObjectSelection objectSelector, String performanceMetric, ThresholdType thresholdType, ThresholdDetails thresholdDetails) throws MonitoringException { if (objectSelector == null) throw new MonitoringException("The objectSelector is null or empty"); if ((performanceMetric == null && performanceMetric.isEmpty())) throw new MonitoringException("The performanceMetric needs to be present"); if (thresholdDetails == null) throw new MonitoringException("The thresholdDetails is null"); //TODO Investigate which are the cases where we need more than one objectSelector //check if media is configured // this is required to allow Zabbix Plugin to receive the notification configureMedia(); //Now we use only one objectSelector List<String> hostnames = objectSelector.getObjectInstanceIds(); Threshold threshold; try { String firstHostname = hostnames.get(0); String thresholdExpression = ""; for (String hostname : hostnames) { String singleHostExpression = ""; if (!hostname.equals(firstHostname)) { if (thresholdDetails.getHostOperator() != null) singleHostExpression += thresholdDetails.getHostOperator(); } singleHostExpression += "{" + hostname + ":" + performanceMetric; if (thresholdDetails.getFunction() != null && !thresholdDetails.getFunction().isEmpty()) singleHostExpression += "." + thresholdDetails.getFunction(); singleHostExpression += "}" + thresholdDetails.getTriggerOperator() + thresholdDetails.getValue(); thresholdExpression += singleHostExpression; } log.debug("Threshold expression: " + thresholdExpression); String triggerId, thresholdName; if (isPrototype(thresholdExpression)) { thresholdName = "PrototypeThreshold on demand " + random.nextInt(100000); triggerId = zabbixApiManager.createPrototypeTrigger(thresholdName, thresholdExpression, getPriority(thresholdDetails.getPerceivedSeverity())); } else { thresholdName = "Threshold on demand " + random.nextInt(100000); triggerId = zabbixApiManager.createTrigger(thresholdName, thresholdExpression, getPriority(thresholdDetails.getPerceivedSeverity())); } threshold = new Threshold(objectSelector, performanceMetric, thresholdType, thresholdDetails); threshold.setThresholdId(triggerId); thresholds.put(threshold.getThresholdId(), threshold); String mediaId = zabbixApiManager.getScriptUserMediaScript(); String mediatypeId = zabbixApiManager.getMediaTypeId(mediaId); //create an action to be notified when this threshold is crossed String actionId = zabbixApiManager.createAction("Action for (" + thresholdName + ")", thresholdName, mediatypeId); triggerIdActionIdMap.put(triggerId, actionId); } catch (Exception e) { throw new MonitoringException("The threshold cannot be created: " + e.getMessage(), e); } return threshold.getThresholdId(); } private void configureMedia() throws MonitoringException { String usermediaId = zabbixApiManager.getScriptUserMediaScript(); if (usermediaId != null) { log.debug("Zabbix already configured to get the notification afterwards"); return; } log.debug("Start Zabbix configuration to get the notification afterwards"); try { // creating mediatype script String mediatypeId = zabbixApiManager.createMediaTypeScript(); // adding the mediatype to the user ADMIN usermediaId = zabbixApiManager.addMedia("1", mediatypeId, zabbixPluginIp); if (usermediaId != null) log.debug("Zabbix configured successfully"); else throw new MonitoringException("The media script has not be created correctly on Zabbix Server"); } catch (Exception e) { log.error( "It was not possible to configure Zabbix Server, such configuration needs to be done manually"); log.debug(e.getMessage(), e); } } @Override public List<String> deleteThreshold(List<String> thresholdIds) throws MonitoringException { if (thresholdIds == null) throw new MonitoringException("The list of thresholdIds ids is null"); if (thresholdIds.isEmpty()) throw new MonitoringException("The list of thresholdIds is empty"); List<String> thresholdIdsDeleted = new ArrayList<>(); try { List<String> triggerIdsToDelete = new ArrayList<>(); List<String> prototypeTriggerIdsToDelete = new ArrayList<>(); for (String thresholdIdToDelete : thresholdIds) { Threshold thresholdToDelete = thresholds.get(thresholdIdToDelete); if (thresholdToDelete != null) { if (isPrototype(thresholdToDelete.getPerformanceMetric())) { prototypeTriggerIdsToDelete.add(thresholdIdToDelete); } else triggerIdsToDelete.add(thresholdIdToDelete); } } List<String> triggerIdsDeleted = new ArrayList<>(); if (triggerIdsToDelete.size() != 0) { triggerIdsDeleted = zabbixApiManager.deleteTriggers(triggerIdsToDelete); if (!triggerIdsToDelete.containsAll(triggerIdsDeleted)) { log.warn("Triggers deleted: " + triggerIdsDeleted + " are less than the Triggers to delete: " + triggerIdsToDelete); } } List<String> prototypeTriggerIdsDeleted = new ArrayList<>(); if (prototypeTriggerIdsToDelete.size() != 0) { prototypeTriggerIdsDeleted = zabbixApiManager.deleteTriggerPrototype(prototypeTriggerIdsToDelete); if (!prototypeTriggerIdsToDelete.containsAll(prototypeTriggerIdsDeleted)) { log.warn("PrototypeTriggers deleted: " + prototypeTriggerIdsDeleted + " are less than the prototypeTriggers to delete: " + prototypeTriggerIdsToDelete); } } //Here we are going to delete the actions linked with the triggers effectively DELETED List<String> actionIdsToDelete = getActions(triggerIdsDeleted); actionIdsToDelete.addAll(getActions(prototypeTriggerIdsDeleted)); List<String> actionIdDeleted = zabbixApiManager.deleteActions(actionIdsToDelete); if (!actionIdsToDelete.containsAll(actionIdDeleted)) { log.warn("Actions deleted: " + actionIdDeleted + " are less than the actions to delete: " + actionIdsToDelete); } //Update the local state List<String> totalTriggerIdsDeleted = new ArrayList<>(); totalTriggerIdsDeleted.addAll(prototypeTriggerIdsDeleted); totalTriggerIdsDeleted.addAll(triggerIdsDeleted); for (String triggerId : totalTriggerIdsDeleted) { thresholds.remove(triggerId); String actionId = triggerIdActionIdMap.get(triggerId); if (!actionIdDeleted.contains(actionId)) log.warn("The action with id:" + actionId + " referred to the trigger id: " + triggerId + " needs to be removed manually on zabbix"); triggerIdActionIdMap.remove(triggerId); } thresholdIdsDeleted = totalTriggerIdsDeleted; } catch (Exception e) { throw new MonitoringException("The thresholds cannot be deleted: " + e.getMessage(), e); } return thresholdIdsDeleted; } private boolean isPrototype(String performanceMetric) { if (performanceMetric.contains("{#FSNAME}") | performanceMetric.contains("{#FSTYPE}") | performanceMetric.contains("{#IFNAME}") | performanceMetric.contains("{#SNMPINDEX}") | performanceMetric.contains("{#SNMPVALUE}")) return true; return false; } private List<String> getActions(List<String> triggerIdDeleted) { List<String> result = new ArrayList<>(); for (String triggerId : triggerIdDeleted) { String actionId = triggerIdActionIdMap.get(triggerId); if (actionId != null) { result.add(actionId); } } return result; } @Override public void queryThreshold(String queryFilter) { } class MyHandler implements HttpHandler { @Override public void handle(HttpExchange t) throws IOException { try (InputStream is = t.getRequestBody()) { String message = read(is); checkRequest(message); t.sendResponseHeaders(200, 0); try (OutputStream os = t.getResponseBody()) { os.close(); } } catch (Exception e) { t.sendResponseHeaders(500, 0); try (OutputStream os = t.getResponseBody()) { os.close(); } log.error(e.getMessage(), e); } } private void checkRequest(String message) throws BadFormatException { log.debug("\n\n"); log.debug("Received: " + message); ZabbixNotification zabbixNotification; try { zabbixNotification = mapper.fromJson(message, ZabbixNotification.class); } catch (JsonSyntaxException e) { throw new BadFormatException( "JsonSyntaxException: Impossible to retrieve the ZabbixNotification received"); } log.debug("\n"); log.debug("ZabbixNotification: " + zabbixNotification); handleNotification(zabbixNotification); } private String read(InputStream is) throws IOException { StringBuilder responseStrBuilder = new StringBuilder(); try (BufferedReader streamReader = new BufferedReader(new InputStreamReader(is, "UTF-8"))) { String inputStr; while ((inputStr = streamReader.readLine()) != null) responseStrBuilder.append(inputStr); } return responseStrBuilder.toString(); } } }