/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2008-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.web.rest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.opennms.core.utils.InetAddressUtils;
import org.opennms.netmgt.EventConstants;
import org.opennms.netmgt.config.CollectdConfigFactory;
import org.opennms.netmgt.config.CollectdPackage;
import org.opennms.netmgt.config.NotifdConfigFactory;
import org.opennms.netmgt.config.PollOutagesConfigFactory;
import org.opennms.netmgt.config.PollerConfigFactory;
import org.opennms.netmgt.config.ThreshdConfigFactory;
import org.opennms.netmgt.config.poller.Outage;
import org.opennms.netmgt.config.poller.Outages;
import org.opennms.netmgt.model.events.EventBuilder;
import org.opennms.netmgt.model.events.EventProxy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import com.sun.jersey.spi.resource.PerRequest;
/**
* <p>ScheduledOutagesRestService class.</p>
*
* <ul>
* <li><b>GET /sched-outages</b><br>to get a list of configured scheduled outages.</li>
* <li><b>POST /sched-outages</b><br>to add a new outage (or update an existing one).</li>
* <li><b>GET /sched-outages/{outageName}</b><br>to get the details of a specific outage.</li>
* <li><b>DELETE /sched-outages/{outageName}</b><br>to delete a specific outage.</li>
* <li><b>PUT /sched-outages/{outageName}/collectd/{package}</b><br>to add a specific outage to a collectd's package.</li>
* <li><b>PUT /sched-outages/{outageName}/pollerd/{package}</b><br>to add a specific outage to a pollerd's package.</li>
* <li><b>PUT /sched-outages/{outageName}/threshd/{package}</b><br>to add a specific outage to a threshd's package.</li>
* <li><b>PUT /sched-outages/{outageName}/notifd</b><br>to add a specific outage to the notifications.</li>
* <li><b>DELETE /sched-outages/{outageName}/collectd/{package}</b><br>to remove a specific outage from a collectd's package.</li>
* <li><b>DELETE /sched-outages/{outageName}/pollerd/{package}</b><br>to remove a specific outage from a pollerd's package.</li>
* <li><b>DELETE /sched-outages/{outageName}/threshd/{package}</b><br>to remove a specific outage from a threshd's package.</li>
* <li><b>DELETE /sched-outages/{outageName}/notifd</b><br>to remove a specific outage from the notifications.</li>
* </ul>
*
* <p>Node and Interface status (the requests return true or false):</p>
* <ul>
* <li><b>GET /sched-outages/{outageName}/nodeInOutage/{nodeId}</b><br>to check if a node (with a specific nodeId) is currently on outage for a specific scheduled outage calendar.</li>
* <li><b>GET /sched-outages/{outageName}/interfaceInOutage/{ipAddr}</b><br>to check if an interface (with a specific IP address) is currently on outage for a specific scheduled outage calendar.</li>
* <li><b>GET /sched-outages/nodeInOutage/{nodeId}</b><br>to check if a node (with a specific nodeId) is currently in outage.</li>
* <li><b>GET /sched-outages/interfaceInOutage/{ipAddr}</b><br>to check if an interface (with a specific IP address) is currently on outage.</li>
* </ul>
*
* @author Alejandro Galue <agalue@opennms.org>
*/
@Component
@PerRequest
@Scope("prototype")
@Path("sched-outages")
public class ScheduledOutagesRestService extends OnmsRestService {
private enum ConfigAction { ADD, REMOVE, REMOVE_FROM_ALL };
@Autowired
protected PollOutagesConfigFactory m_configFactory;
@Autowired
protected EventProxy m_eventProxy;
@GET
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Outages getOutages() {
readLock();
try {
Outages outages = new Outages();
outages.setOutage(m_configFactory.getOutages());
return outages;
} finally {
readUnlock();
}
}
@GET
@Path("{outageName}")
@Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Outage getOutage(@PathParam("outageName") String outageName) throws IllegalArgumentException {
readLock();
try {
Outage outage = m_configFactory.getOutage(outageName);
if (outage == null) throw new IllegalArgumentException("Scheduled outage " + outageName + " does not exist.");
return outage;
} finally {
readUnlock();
}
}
@POST
@Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
public Response saveOrUpdateOutage(final Outage newOutage) {
writeLock();
try {
if (newOutage == null) throw getException(Status.BAD_REQUEST, "Outage object can't be null");
Outage oldOutage = m_configFactory.getOutage(newOutage.getName());
if (oldOutage == null) {
log().debug("saveOrUpdateOutage: adding outage " + newOutage.getName());
m_configFactory.addOutage(newOutage);
} else {
log().debug("saveOrUpdateOutage: updating outage " + newOutage.getName());
m_configFactory.replaceOutage(oldOutage, newOutage);
}
m_configFactory.saveCurrent();
sendConfigChangedEvent();
return Response.ok().build();
} catch (Exception e) {
throw getException(Status.BAD_REQUEST, "Can't save or update the scheduled outage " + newOutage.getName() + " because, " + e.getMessage());
} finally {
writeUnlock();
}
}
@DELETE
@Path("{outageName}")
public Response deleteOutage(@PathParam("outageName") String outageName) {
writeLock();
try {
log().debug("deleteOutage: deleting outage " + outageName);
updateCollectd(ConfigAction.REMOVE_FROM_ALL, outageName, null);
updatePollerd(ConfigAction.REMOVE_FROM_ALL, outageName, null);
updateThreshd(ConfigAction.REMOVE_FROM_ALL, outageName, null);
updateNotifd(ConfigAction.REMOVE, outageName);
m_configFactory.removeOutage(outageName);
m_configFactory.saveCurrent();
sendConfigChangedEvent();
return Response.ok().build();
} catch (Exception e) {
throw getException(Status.BAD_REQUEST, "Can't delete the scheduled outage " + outageName + " because, " + e.getMessage());
} finally {
writeUnlock();
}
}
@PUT
@Path("{outageName}/collectd/{packageName}")
public Response addOutageToCollector(@PathParam("outageName") String outageName, @PathParam("packageName") String packageName) {
writeLock();
try {
updateCollectd(ConfigAction.ADD, outageName, packageName);
sendConfigChangedEvent();
return Response.ok().build();
} catch (Exception e) {
throw getException(Status.BAD_REQUEST, "Can't add scheduled outage " + outageName + " to collector package " + packageName + ", because: " + e.getMessage());
} finally {
writeUnlock();
}
}
@DELETE
@Path("{outageName}/collectd/{packageName}")
public Response removeOutageFromCollector(@PathParam("outageName") String outageName, @PathParam("packageName") String packageName) {
writeLock();
try {
updateCollectd(ConfigAction.REMOVE, outageName, packageName);
sendConfigChangedEvent();
return Response.ok().build();
} catch (Exception e) {
throw getException(Status.BAD_REQUEST, "Can't remove scheduled outage " + outageName + " from collector package " + packageName + ", because: " + e.getMessage());
} finally {
writeUnlock();
}
}
@PUT
@Path("{outageName}/pollerd/{packageName}")
public Response addOutageToPoller(@PathParam("outageName") String outageName, @PathParam("packageName") String packageName) {
writeLock();
try {
updatePollerd(ConfigAction.ADD, outageName, packageName);
sendConfigChangedEvent();
return Response.ok().build();
} catch (Exception e) {
throw getException(Status.BAD_REQUEST, "Can't add scheduled outage " + outageName + " to poller package " + packageName + ", because: " + e.getMessage());
} finally {
writeUnlock();
}
}
@DELETE
@Path("{outageName}/pollerd/{packageName}")
public Response removeOutageFromPoller(@PathParam("outageName") String outageName, @PathParam("packageName") String packageName) {
writeLock();
try {
updatePollerd(ConfigAction.REMOVE, outageName, packageName);
sendConfigChangedEvent();
return Response.ok().build();
} catch (Exception e) {
throw getException(Status.BAD_REQUEST, "Can't remove scheduled outage " + outageName + " from poller package " + packageName + ", because: " + e.getMessage());
} finally {
writeUnlock();
}
}
@PUT
@Path("{outageName}/threshd/{packageName}")
public Response addOutageToThresholder(@PathParam("outageName") String outageName, @PathParam("packageName") String packageName) {
writeLock();
try {
updateThreshd(ConfigAction.ADD, outageName, packageName);
sendConfigChangedEvent();
return Response.ok().build();
} catch (Exception e) {
throw getException(Status.BAD_REQUEST, "Can't add scheduled outage " + outageName + " to threshold package " + packageName + ", because: " + e.getMessage());
} finally {
writeUnlock();
}
}
@DELETE
@Path("{outageName}/threshd/{packageName}")
public Response removeOutageFromThresholder(@PathParam("outageName") String outageName, @PathParam("packageName") String packageName) {
writeLock();
try {
updateThreshd(ConfigAction.REMOVE, outageName, packageName);
sendConfigChangedEvent();
return Response.ok().build();
} catch (Exception e) {
throw getException(Status.BAD_REQUEST, "Can't remove scheduled outage " + outageName + " from threshold package " + packageName + ", because: " + e.getMessage());
} finally {
writeUnlock();
}
}
@PUT
@Path("{outageName}/notifd")
public Response addOutageToNotifications(@PathParam("outageName") String outageName) {
writeLock();
try {
updateNotifd(ConfigAction.ADD, outageName);
sendConfigChangedEvent();
return Response.ok().build();
} catch (Exception e) {
throw getException(Status.BAD_REQUEST, "Can't add scheduled outage " + outageName + " to notifications because: " + e.getMessage());
} finally {
writeUnlock();
}
}
@DELETE
@Path("{outageName}/notifd")
public Response removeOutageFromNotifications(@PathParam("outageName") String outageName) {
writeLock();
try {
updateNotifd(ConfigAction.REMOVE, outageName);
sendConfigChangedEvent();
return Response.ok().build();
} catch (Exception e) {
throw getException(Status.BAD_REQUEST, "Can't remove scheduled outage " + outageName + " from notifications because: " + e.getMessage());
} finally {
writeUnlock();
}
}
@GET
@Path("{outageName}/nodeInOutage/{nodeId}")
@Produces(MediaType.TEXT_PLAIN)
public String isNodeInOutage(@PathParam("outageName") String outageName, @PathParam("nodeId") Integer nodeId) {
readLock();
try {
Outage outage = getOutage(outageName);
Boolean inOutage = m_configFactory.isNodeIdInOutage(nodeId, outage) && m_configFactory.isCurTimeInOutage(outage);
return inOutage.toString();
} finally {
readUnlock();
}
}
@GET
@Path("nodeInOutage/{nodeId}")
@Produces(MediaType.TEXT_PLAIN)
public String isNodeInOutage(@PathParam("nodeId") Integer nodeId) {
readLock();
try {
for (Outage outage : m_configFactory.getOutages()) {
if (m_configFactory.isNodeIdInOutage(nodeId, outage) && m_configFactory.isCurTimeInOutage(outage)) {
return Boolean.TRUE.toString();
}
}
return Boolean.FALSE.toString();
} finally {
readUnlock();
}
}
@GET
@Path("{outageName}/interfaceInOutage/{ipAddr}")
@Produces(MediaType.TEXT_PLAIN)
public String isInterfaceInOutage(@PathParam("outageName") String outageName, @PathParam("ipAddr") String ipAddr) {
readLock();
try {
validateAddress(ipAddr);
Outage outage = getOutage(outageName);
Boolean inOutage = m_configFactory.isInterfaceInOutage(ipAddr, outage) && m_configFactory.isCurTimeInOutage(outage);
return inOutage.toString();
} finally {
readUnlock();
}
}
@GET
@Path("interfaceInOutage/{ipAddr}")
@Produces(MediaType.TEXT_PLAIN)
public String isInterfaceInOutage(@PathParam("ipAddr") String ipAddr) {
readLock();
try {
for (Outage outage : m_configFactory.getOutages()) {
if (m_configFactory.isInterfaceInOutage(ipAddr, outage) && m_configFactory.isCurTimeInOutage(outage)) {
return Boolean.TRUE.toString();
}
}
return Boolean.FALSE.toString();
} finally {
readUnlock();
}
}
private void validateAddress(String ipAddress) {
boolean valid = false;
try {
valid = InetAddressUtils.addr(ipAddress) != null;
} catch (Exception e) {
valid = false;
}
if (!valid) {
throw getException(Status.BAD_REQUEST, "Malformed IP Address " + ipAddress);
}
}
private void updateCollectd(ConfigAction action, String outageName, String packageName) throws Exception {
getOutage(outageName); // Validate if outageName exists.
if (action.equals(ConfigAction.ADD)) {
CollectdPackage pkg = getCollectdPackage(packageName);
if (!pkg.getPackage().getOutageCalendarCollection().contains(outageName))
pkg.getPackage().addOutageCalendar(outageName);
}
if (action.equals(ConfigAction.REMOVE)) {
CollectdPackage pkg = getCollectdPackage(packageName);
pkg.getPackage().removeOutageCalendar(outageName);
}
if (action.equals(ConfigAction.REMOVE_FROM_ALL)) {
for (CollectdPackage pkg : CollectdConfigFactory.getInstance().getCollectdConfig().getPackages()) {
pkg.getPackage().removeOutageCalendar(outageName);
}
}
CollectdConfigFactory.getInstance().saveCurrent();
}
private CollectdPackage getCollectdPackage(String packageName) throws IllegalArgumentException {
CollectdPackage pkg = CollectdConfigFactory.getInstance().getPackage(packageName);
if (pkg == null) throw new IllegalArgumentException("Collectd package " + packageName + " does not exist.");
return pkg;
}
private void updatePollerd(ConfigAction action, String outageName, String packageName) throws Exception {
getOutage(outageName); // Validate if outageName exists.
if (action.equals(ConfigAction.ADD)) {
org.opennms.netmgt.config.poller.Package pkg = getPollerdPackage(packageName);
if (!pkg.getOutageCalendarCollection().contains(outageName))
pkg.addOutageCalendar(outageName);
}
if (action.equals(ConfigAction.REMOVE)) {
org.opennms.netmgt.config.poller.Package pkg = getPollerdPackage(packageName);
pkg.removeOutageCalendar(outageName);
}
if (action.equals(ConfigAction.REMOVE_FROM_ALL)) {
for (org.opennms.netmgt.config.poller.Package pkg : PollerConfigFactory.getInstance().getConfiguration().getPackage()) {
pkg.removeOutageCalendar(outageName);
}
}
PollerConfigFactory.getInstance().save();
}
private org.opennms.netmgt.config.poller.Package getPollerdPackage(String packageName) throws IllegalArgumentException {
org.opennms.netmgt.config.poller.Package pkg = PollerConfigFactory.getInstance().getPackage(packageName);
if (pkg == null) throw new IllegalArgumentException("Poller package " + packageName + " does not exist.");
return pkg;
}
private void updateThreshd(ConfigAction action, String outageName, String packageName) throws Exception {
getOutage(outageName); // Validate if outageName exists.
if (action.equals(ConfigAction.ADD)) {
org.opennms.netmgt.config.threshd.Package pkg = getThreshdPackage(packageName);
if (!pkg.getOutageCalendarCollection().contains(outageName))
pkg.addOutageCalendar(outageName);
}
if (action.equals(ConfigAction.REMOVE)) {
org.opennms.netmgt.config.threshd.Package pkg = getThreshdPackage(packageName);
pkg.removeOutageCalendar(outageName);
}
if (action.equals(ConfigAction.REMOVE_FROM_ALL)) {
for (org.opennms.netmgt.config.threshd.Package pkg : ThreshdConfigFactory.getInstance().getConfiguration().getPackage()) {
pkg.removeOutageCalendar(outageName);
}
}
ThreshdConfigFactory.getInstance().saveCurrent();
}
private org.opennms.netmgt.config.threshd.Package getThreshdPackage(String packageName) throws IllegalArgumentException {
org.opennms.netmgt.config.threshd.Package pkg = ThreshdConfigFactory.getInstance().getPackage(packageName);
if (pkg == null) throw new IllegalArgumentException("Threshold package " + packageName + " does not exist.");
return pkg;
}
private void updateNotifd(ConfigAction action, String outageName) throws Exception {
getOutage(outageName); // Validate if outageName exists.
NotifdConfigFactory factory = NotifdConfigFactory.getInstance();
if (action.equals(ConfigAction.ADD)) {
factory.getConfiguration().addOutageCalendar(outageName);
}
if (action.equals(ConfigAction.REMOVE) || action.equals(ConfigAction.REMOVE_FROM_ALL)) {
factory.getConfiguration().removeOutageCalendar(outageName);
}
factory.saveCurrent();
}
private void sendConfigChangedEvent() {
EventBuilder builder = new EventBuilder(EventConstants.SCHEDOUTAGES_CHANGED_EVENT_UEI, "Web UI");
try {
m_eventProxy.send(builder.getEvent());
} catch (Throwable e) {
throw getException(Status.BAD_REQUEST, "Could not send event " + builder.getEvent().getUei() + " because, " + e.getMessage());
}
}
}