onl.netfishers.netshot.compliance.Rule.java Source code

Java tutorial

Introduction

Here is the source code for onl.netfishers.netshot.compliance.Rule.java

Source

/**
 * Copyright 2013-2016 Sylvain Cadilhac (NetFishers)
 * 
 * This file is part of Netshot.
 * 
 * Netshot 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.
 * 
 * Netshot 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 Netshot.  If not, see <http://www.gnu.org/licenses/>.
 */
package onl.netfishers.netshot.compliance;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import onl.netfishers.netshot.compliance.CheckResult.ResultOption;
import onl.netfishers.netshot.compliance.rules.JavaScriptRule;
import onl.netfishers.netshot.compliance.rules.TextRule;
import onl.netfishers.netshot.device.Device;
import onl.netfishers.netshot.device.DeviceDriver;
import onl.netfishers.netshot.device.Device.MissingDeviceDriverException;
import onl.netfishers.netshot.device.DeviceDriver.AttributeDefinition;
import onl.netfishers.netshot.device.DeviceDriver.AttributeLevel;
import onl.netfishers.netshot.device.Module;
import onl.netfishers.netshot.device.Network4Address;
import onl.netfishers.netshot.device.Network6Address;
import onl.netfishers.netshot.device.NetworkInterface;
import onl.netfishers.netshot.device.attribute.ConfigAttribute;
import onl.netfishers.netshot.device.attribute.DeviceAttribute;

import org.hibernate.HibernateException;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.annotation.JsonTypeInfo;

/**
 * A rule defines a number of constraints that a device should comply with.
 * A concrete implementation is the Javascript-based script rule.
 */
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(uniqueConstraints = { @UniqueConstraint(columnNames = { "policy", "name" }) })
@XmlRootElement
@XmlAccessorType(value = XmlAccessType.NONE)
@JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, include = JsonTypeInfo.As.PROPERTY, property = "type")
public abstract class Rule {

    /** The logger. */
    private static Logger logger = LoggerFactory.getLogger(Rule.class);

    /** The set of real rule types. */
    private static final Set<Class<? extends Rule>> RULE_CLASSES;

    static {
        RULE_CLASSES = new HashSet<Class<? extends Rule>>();
        RULE_CLASSES.add(JavaScriptRule.class);
        RULE_CLASSES.add(TextRule.class);
    }

    /**
     * Gets the rule classes.
     *
     * @return the rule classes
     */
    public static final Set<Class<? extends Rule>> getRuleClasses() {
        return RULE_CLASSES;
    }

    /**
     * The Class RuleDataProvider.
     */
    public class RuleDataProvider {

        /** The device. */
        private Device device = null;

        /** The session. */
        private Session session;

        /**
         * Instantiates a new js data provider.
         *
         * @param session the session
         * @param device the device
         */
        public RuleDataProvider(Session session, Device device) {
            this.session = session;
            this.device = device;
        }

        /**
         * Gets the device item.
         *
         * @param device the device
         * @param item the item
         * @return the device item
         */
        private Object getDeviceItem(Device device, String item) {
            DeviceDriver driver;
            try {
                driver = device.getDeviceDriver();
            } catch (MissingDeviceDriverException e) {
                return null;
            }
            if ("type".equals(item)) {
                return driver.getDescription();
            } else if ("name".equals(item)) {
                return device.getName();
            } else if ("family".equals(item)) {
                return device.getFamily();
            } else if ("location".equals(item)) {
                return device.getLocation();
            } else if ("contact".equals(item)) {
                return device.getContact();
            } else if ("softwareVersion".equals(item)) {
                return device.getSoftwareVersion();
            } else if ("serialNumber".equals(item)) {
                return device.getSerialNumber();
            } else if ("networkClass".equals(item)) {
                return (device.getNetworkClass() == null ? null : device.getNetworkClass().toString());
            } else if ("virtualDevices".equals(item)) {
                return device.getVirtualDevices().toArray();
            } else if ("vrfs".equals(item)) {
                return device.getVrfInstances().toArray();
            } else if ("modules".equals(item)) {
                List<Map<String, String>> modules = new ArrayList<Map<String, String>>();
                for (Module m : device.getModules()) {
                    Map<String, String> module = new HashMap<String, String>();
                    module.put("slot", m.getSlot());
                    module.put("partNumber", m.getPartNumber());
                    module.put("serialNumber", m.getSerialNumber());
                    modules.add(module);
                }
                return modules.toArray();
            } else if ("interfaces".equals(item)) {
                List<Map<String, Object>> networkInterfaces = new ArrayList<Map<String, Object>>();
                for (NetworkInterface ni : device.getNetworkInterfaces()) {
                    Map<String, Object> networkInterface = new HashMap<String, Object>();
                    networkInterface.put("name", ni.getInterfaceName());
                    networkInterface.put("description", ni.getDescription());
                    networkInterface.put("mac", ni.getMacAddress());
                    networkInterface.put("virtualDevice", ni.getVirtualDevice());
                    networkInterface.put("vrf", ni.getVrfInstance());
                    List<Map<String, String>> ips = new ArrayList<Map<String, String>>();
                    for (Network4Address address : ni.getIp4Addresses()) {
                        Map<String, String> ip = new HashMap<String, String>();
                        ip.put("ip", address.getIp());
                        ip.put("mask", Integer.toString(address.getPrefixLength()));
                        ip.put("usage", address.getAddressUsage().toString());
                        ips.add(ip);
                    }
                    for (Network6Address address : ni.getIp6Addresses()) {
                        Map<String, String> ip = new HashMap<String, String>();
                        ip.put("ipv6", address.getIp());
                        ip.put("mask", Integer.toString(address.getPrefixLength()));
                        ip.put("usage", address.getAddressUsage().toString());
                        ips.add(ip);
                    }
                    networkInterface.put("ip", ips.toArray());
                    networkInterfaces.add(networkInterface);
                }
                return networkInterfaces.toArray();
            } else {
                for (AttributeDefinition definition : driver.getAttributes()) {
                    if ((definition.getName().equals(item) || definition.getTitle().equals(item))
                            && definition.isCheckable()) {
                        if (definition.getLevel() == AttributeLevel.CONFIG && device.getLastConfig() != null) {
                            for (ConfigAttribute attribute : device.getLastConfig().getAttributes()) {
                                if (attribute.getName().equals(item)) {
                                    return attribute.getData();
                                }
                            }
                        } else if (definition.getLevel() == AttributeLevel.DEVICE) {
                            for (DeviceAttribute attribute : device.getAttributes()) {
                                if (attribute.getName().equals(item)) {
                                    return attribute.getData();
                                }
                            }
                        }
                    }
                }
            }
            return null;
        }

        /**
         * Gets the.
         *
         * @param item the item
         * @return the object
         */
        public Object get(String item) {
            logger.debug("JavaScript request for item {} on current device.", item);
            return this.getDeviceItem(this.device, item);
        }

        /**
         * Load device.
         *
         * @param id the id
         * @return the device
         * @throws HibernateException the hibernate exception
         */
        private Device loadDevice(long id) throws HibernateException {
            Device device = (Device) session.createQuery("from Device d join fetch d.lastConfig where d.id = :id")
                    .setLong("id", id).uniqueResult();
            return device;
        }

        private Device loadDevice(String name) throws HibernateException {
            Device device = (Device) session
                    .createQuery("from Device d join fetch d.lastConfig where d.name = :name")
                    .setString("name", name).uniqueResult();
            return device;
        }

        /**
         * Destroy.
         */
        public void destroy() {
        }

        /**
         * Gets the.
         *
         * @param item the item
         * @param deviceId the device id
         * @return the object
         */
        public Object get(String item, long deviceId) {
            logger.debug("JavaScript request for item {} on device {}.", item, deviceId);
            if (deviceId == this.device.getId()) {
                return this.get(item);
            }
            try {
                device = loadDevice(deviceId);
                Object result = this.getDeviceItem(device, item);
                session.evict(device);
                return result;
            } catch (ObjectNotFoundException e) {
                logger.error("Device not found on JavaScript get, item {}, device {}.", item, deviceId, e);
                logIt(String.format("Unable to find the device %d.", deviceId), 3);
            } catch (Exception e) {
                logger.error("Error on JavaScript get, item {}, device {}.", item, deviceId, e);
                logIt(String.format("Unable to get data %s for device %d.", deviceId), 3);
            }
            return null;
        }

        public Object get(String item, String deviceName) {
            logger.debug("JavaScript request for item {} on device named {}.", item, deviceName);
            try {
                if (device.getName().equals(deviceName)) {
                    return this.get(item);
                }
                device = loadDevice(deviceName);
                Object result = this.getDeviceItem(device, item);
                session.evict(device);
                return result;
            } catch (ObjectNotFoundException e) {
                logger.error("Device not found on JavaScript get, item {}, device named {}.", item, deviceName, e);
                logIt(String.format("Unable to find the device named %s.", deviceName), 3);
            } catch (Exception e) {
                logger.error("Error on JavaScript get, item {}, device named {}.", item, deviceName, e);
                logIt(String.format("Unable to get data %s for device named %s.", deviceName), 3);
            }
            return null;
        }

        /**
         * Nslookup.
         *
         * @param host the host
         * @return the object
         */
        public Object nslookup(String host) {
            String name = "";
            String address = "";
            try {
                InetAddress ip = InetAddress.getByName(host);
                name = ip.getHostName();
                address = ip.getHostAddress();
            } catch (UnknownHostException e) {
            }
            Map<String, String> result = new HashMap<String, String>();
            result.put("name", name);
            result.put("address", address);
            return result;
        }

        /**
         * Debug.
         *
         * @param message the message
         */
        public void debug(String message) {
            logIt("DEBUG: " + message, 5);
        }

    }

    /** The enabled. */
    protected boolean enabled = false;

    /** The id. */
    protected long id;

    /** The policy. */
    protected Policy policy = null;

    /** The name. */
    protected String name = "";

    /** The log. */
    private List<String> log = new ArrayList<String>();

    /** The exemptions. */
    private Set<Exemption> exemptions = new HashSet<Exemption>();

    /** The check results. */
    private Set<CheckResult> checkResults = new HashSet<CheckResult>();

    /**
     * Instantiates a new rule.
     */
    protected Rule() {

    }

    /**
     * Instantiates a new rule.
     *
     * @param name the name
     * @param policy the policy
     */
    public Rule(String name, Policy policy) {
        this.name = name;
        this.policy = policy;
    }

    /**
     * Sets the check result.
     *
     * @param device the device
     * @param result the result
     * @param comment the comment
     * @param session the session
     */
    protected void setCheckResult(Device device, CheckResult.ResultOption result, String comment, Session session) {
        CheckResult checkResult = new CheckResult(this, device, result);
        checkResult.setComment(comment);
        if (session.contains(this)) {
            session.saveOrUpdate(checkResult);
        } else {
            this.checkResults.add(checkResult);
        }
    }

    /**
     * Check.
     *
     * @param device the device
     * @param session the session
     */
    public void check(Device device, Session session) {
        logger.warn("Called generic rule check.");
        if (!this.isEnabled()) {
            this.setCheckResult(device, ResultOption.DISABLED, "", session);
        } else if (device.isExempted(this)) {
            this.setCheckResult(device, ResultOption.EXEMPTED, "", session);
        } else {
            this.setCheckResult(device, ResultOption.NOTAPPLICABLE, "", session);
        }
    }

    /* (non-Javadoc)
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Rule other = (Rule) obj;
        if (id != other.id)
            return false;
        return true;
    }

    /**
     * Gets the id.
     *
     * @return the id
     */
    @Id
    @GeneratedValue
    @XmlElement
    public long getId() {
        return id;
    }

    /**
     * Gets the policy.
     *
     * @return the policy
     */
    @ManyToOne
    public Policy getPolicy() {
        return policy;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (int) (id ^ (id >>> 32));
        return result;
    }

    /**
     * Checks if is enabled.
     *
     * @return true, if is enabled
     */
    @XmlElement
    public boolean isEnabled() {
        return enabled;
    }

    /**
     * Sets the enabled.
     *
     * @param enabled the new enabled
     */
    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    /**
     * Sets the id.
     *
     * @param id the new id
     */
    public void setId(long id) {
        this.id = id;
    }

    /**
     * Sets the policy.
     *
     * @param policy the new policy
     */
    public void setPolicy(Policy policy) {
        this.policy = policy;
    }

    /**
     * Gets the name.
     *
     * @return the name
     */
    @XmlElement
    public String getName() {
        return name;
    }

    /**
     * Sets the name.
     *
     * @param name the new name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * Gets the log.
     *
     * @return the log
     */
    @Transient
    public List<String> getLog() {
        return log;
    }

    /**
     * Gets the plain log.
     *
     * @return the plain log
     */
    @Transient
    public String getPlainLog() {
        StringBuffer buffer = new StringBuffer();
        for (String log : this.log) {
            buffer.append(log);
            buffer.append("\n");
        }
        return buffer.toString();
    }

    /**
     * Log it.
     *
     * @param log the log
     * @param level the level
     */
    protected void logIt(String log, int level) {
        this.log.add("[" + level + "] " + log);
    }

    /**
     * Gets the exemptions.
     *
     * @return the exemptions
     */
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "key.rule", cascade = CascadeType.ALL, orphanRemoval = true)
    public Set<Exemption> getExemptions() {
        return exemptions;
    }

    /**
     * Sets the exemptions.
     *
     * @param exemptions the new exemptions
     */
    public void setExemptions(Set<Exemption> exemptions) {
        this.exemptions = exemptions;
    }

    /**
     * Delete exemption.
     *
     * @param exemption the exemption
     */
    public void deleteExemption(Exemption exemption) {
        this.exemptions.remove(exemption);
    }

    /**
     * Adds the exemption.
     *
     * @param exemption the exemption
     */
    public void addExemption(Exemption exemption) {
        this.exemptions.add(exemption);
    }

    /**
     * Clear exemptions.
     */
    public void clearExemptions() {
        this.exemptions.clear();
    }

    /**
     * Gets the check results.
     *
     * @return the check results
     */
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "key.rule", cascade = CascadeType.ALL, orphanRemoval = true)
    public Set<CheckResult> getCheckResults() {
        return checkResults;
    }

    /**
     * Sets the check results.
     *
     * @param checkResults the new check results
     */
    public void setCheckResults(Set<CheckResult> checkResults) {
        this.checkResults = checkResults;
    }

    /**
     * Delete check result.
     *
     * @param checkResult the check result
     * @return true, if successful
     */
    public boolean deleteCheckResult(CheckResult checkResult) {
        return this.checkResults.remove(checkResult);
    }

    /**
     * Adds the check result.
     *
     * @param checkResult the check result
     * @return true, if successful
     */
    public boolean addCheckResult(CheckResult checkResult) {
        return this.checkResults.add(checkResult);
    }

    /**
     * Clear check results.
     */
    public void clearCheckResults() {
        this.checkResults.clear();
    }

}