com.dell.asm.asmcore.asmmanager.util.discovery.DeviceTypeCheckUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.dell.asm.asmcore.asmmanager.util.discovery.DeviceTypeCheckUtil.java

Source

/**************************************************************************
 *   Copyright (c) 2012 Dell Inc. All rights reserved.                    *
 *                                                                        *
 * DELL INC. CONFIDENTIAL AND PROPRIETARY INFORMATION. This software may  *
 * only be supplied under the terms of a license agreement or             *
 * nondisclosure agreement with Dell Inc. and may not be copied or        *
 * disclosed except in accordance with the terms of such agreement.       *
 **************************************************************************/
package com.dell.asm.asmcore.asmmanager.util.discovery;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.dell.asm.asmcore.asmmanager.app.AsmManagerApp;
import com.dell.asm.asmcore.asmmanager.client.discovery.DeviceType;
import com.dell.asm.asmcore.asmmanager.client.discovery.DiscoverDeviceType;
import com.dell.asm.common.model.CommandResponse;
import com.dell.asm.common.utilities.ExecuteSystemCommands;
import com.dell.pg.orion.common.utilities.ConfigurationUtils;
import com.dell.pg.orion.common.utilities.MarshalUtil;
import com.dell.pg.orion.security.credential.CredentialDAO;
import com.dell.pg.orion.security.credential.entity.CredentialEntity;
import com.dell.pg.orion.security.credential.entity.StorageCredentialEntity;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

import expect4j.Closure;
import expect4j.Expect4j;
import expect4j.ExpectState;
import expect4j.matches.Match;
import expect4j.matches.RegExpMatch;

/**
 * Device check utility to figure out the device type given an IP address
 */
public final class DeviceTypeCheckUtil {
    public static final String PROP_TEST_INVENTORY_PATH = "com.dell.asm.asmcore.sample.inventory";
    public static final String TEMP_PATH = "/tmp";
    private static final Logger LOGGER = Logger.getLogger(DeviceTypeCheckUtil.class);

    static final SampleInventory SAMPLE_INVENTORY = buildSampleInventory();
    private static final String EQUALLOGIC_MANAGEMENT_IP = "Management-Ipaddress";
    private static final String EQUALLOGIC_GROUP_IP = "Group-Ipaddress";
    private static final String PUPPET_EQL_PATH = "/etc/puppetlabs/puppet/modules/equallogic/files/";
    public static final String PUPPET_SCVMM_PATH = "/etc/puppetlabs/puppet/modules/scvmm";
    public static final String SCVMM_CACHE_PATH = "/opt/Dell/ASM/cache";
    public static final String PUPPET_NETAPP_PATH = "/etc/puppetlabs/puppet/modules/netapp";
    public static final String PUPPET_EMC_VNX_PATH = "/etc/puppetlabs/puppet/modules/vnx";

    @XmlRootElement
    static class SampleInventory {
        private Map<String, DiscoverDeviceType> inventory = new HashMap<>();

        public Map<String, DiscoverDeviceType> getInventory() {
            return inventory;
        }

        public void setInventory(Map<String, DiscoverDeviceType> inventory) {
            this.inventory = inventory;
        }

        public void addInventory(String ipAddres, DiscoverDeviceType deviceType) {
            inventory.put(ipAddres, deviceType);
        }
    }

    private static SampleInventory buildSampleInventory() {
        String path = System.getProperty(PROP_TEST_INVENTORY_PATH);
        if (StringUtils.isBlank(path)) {
            return null;
        } else {
            try {
                URL url = ConfigurationUtils.resolvePropertiesFile(path, SampleInventory.class.getClassLoader());
                String xml = IOUtils.toString(url);
                return MarshalUtil.unmarshal(SampleInventory.class, xml);
            } catch (IllegalStateException e) {
                LOGGER.error("Failed to unmarshal inventory file at " + path, e);
                return null;
            } catch (IOException e) {
                LOGGER.error("Failed to read sample inventory file at " + path, e);
                return null;
            }
        }
    }

    private DeviceTypeCheckUtil() {
    }

    /**
     * HTTP request extractor
     *
     * @param urlToRead device URL
     * @return device type string
     * @throws IOException
     */
    public static String getHTML(String urlToRead) throws IOException {
        URL url;
        HttpURLConnection conn;
        BufferedReader rd = null;
        String line;
        StringBuffer result = new StringBuffer();

        try {
            url = new URL(urlToRead);
            conn = (HttpURLConnection) url.openConnection();
            if (conn instanceof HttpsURLConnection) {
                HttpsURLConnection sslConn = (HttpsURLConnection) conn;
                sslConn.setHostnameVerifier(hv);
                SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, new TrustManager[] { tmNoCheck }, new SecureRandom());
                sslConn.setSSLSocketFactory(sslContext.getSocketFactory());
            }

            conn.setRequestMethod("GET");
            conn.setConnectTimeout(AsmManagerApp.CONNECT_TIMEOUT); // timeout value
            conn.setReadTimeout(AsmManagerApp.CONNECT_TIMEOUT);
            rd = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
            while ((line = rd.readLine()) != null) {
                result.append(line);
            }
        } catch (RuntimeException e) {
            throw new IOException("Could not connect to the url: " + e.getMessage());
        } catch (Exception e) {
            throw new IOException("Could not connect to the url: " + urlToRead);
        } finally {
            if (rd != null)
                rd.close();
        }
        return result.toString();
    }

    /**
     * HTTP POST with basic auth
     *
     * @param urlToRead device URL
     * @return http response message
     * @throws IOException
     */
    public static String httpPost(String urlToRead, String username, String password) throws IOException {
        URL url;
        HttpURLConnection conn;
        BufferedReader rd = null;
        String line;
        StringBuffer result = new StringBuffer();

        try {
            url = new URL(urlToRead);
            conn = (HttpURLConnection) url.openConnection();
            if (conn instanceof HttpsURLConnection) {
                HttpsURLConnection sslConn = (HttpsURLConnection) conn;
                sslConn.setHostnameVerifier(hv);
                SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, new TrustManager[] { tmNoCheck }, new SecureRandom());
                sslConn.setSSLSocketFactory(sslContext.getSocketFactory());
            }
            conn.setDoOutput(true);
            conn.setConnectTimeout(AsmManagerApp.CONNECT_TIMEOUT); // timeout value
            conn.setReadTimeout(AsmManagerApp.CONNECT_TIMEOUT);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("x-dell-api-version", "2.0");
            conn.setRequestProperty("Authorization", encodeCredentials(username, password));
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setFixedLengthStreamingMode("{}".length());
            conn.getOutputStream().write("{}".getBytes(Charset.forName("UTF-8")));

            rd = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
            while ((line = rd.readLine()) != null) {
                result.append(line);
            }
        } catch (RuntimeException e) {
            throw new IOException("Could not connect to the url: " + e.getMessage());
        } catch (Exception e) {
            throw new IOException("Could not connect to the url: " + urlToRead);
        } finally {
            if (rd != null)
                rd.close();
        }
        return result.toString();
    }

    public static int httpGet(String urlToRead) throws IOException {
        URL url;
        HttpURLConnection conn;
        BufferedReader rd = null;
        StringBuffer result = new StringBuffer();
        int responseCode = 400;

        try {
            url = new URL(urlToRead);
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(10);
            responseCode = conn.getResponseCode();

        } catch (RuntimeException e) {
            throw new IOException("Could not connect to the url: " + e.getMessage());
        } catch (Exception e) {
            throw new IOException("Could not connect to the url: " + urlToRead);
        } finally {
            if (rd != null)
                rd.close();
        }
        return responseCode;
    }

    private static String encodeCredentials(String username, String password) {
        return "Basic {"
                + Base64.encodeBase64URLSafeString((username + ":" + password).getBytes(Charset.forName("UTF-8")))
                + "}";
    }

    public static DiscoverDeviceType checkDeviceType(InfrastructureDevice device) {
        if (SAMPLE_INVENTORY != null && SAMPLE_INVENTORY.getInventory().get(device.getIpAddress()) != null) {
            return SAMPLE_INVENTORY.getInventory().get(device.getIpAddress());
        }

        DiscoverDeviceType retVal = DiscoverDeviceType.UNKNOWN;

        if ((device.getRequestedDeviceType() == null || DeviceType.isChassis(device.getRequestedDeviceType()))
                && StringUtils.isNotEmpty(device.getChassisCredentialId())) {
            retVal = checkIdracCmc(device.getIpAddress(), device);
            if (retVal != DiscoverDeviceType.UNKNOWN)
                return retVal;
        }
        if ((device.getRequestedDeviceType() == null || DeviceType.isServer(device.getRequestedDeviceType()))
                && StringUtils.isNotEmpty(device.getServerCredentialId())) {
            retVal = checkIdracCmc(device.getIpAddress(), device);
            if (retVal != DiscoverDeviceType.UNKNOWN)
                return retVal;
            retVal = checkCServer(device.getIpAddress(), device);
            if (retVal != DiscoverDeviceType.UNKNOWN)
                return retVal;
        }
        if ((device.getRequestedDeviceType() == null || DeviceType.isSwitch(device.getRequestedDeviceType()))
                && StringUtils.isNotEmpty(device.getSwitchCredentiallId())) {
            retVal = checkBrocade(device.getIpAddress(), device);
            if (retVal != DiscoverDeviceType.UNKNOWN)
                return retVal;
            retVal = checkForce10(device.getIpAddress(), device);
            if (retVal != DiscoverDeviceType.UNKNOWN)
                return retVal;
            retVal = checkPowerConnect(device.getIpAddress(), device);
            if (retVal != DiscoverDeviceType.UNKNOWN)
                return retVal;
            retVal = checkCiscoNexus(device.getIpAddress(), device);
            if (retVal != DiscoverDeviceType.UNKNOWN)
                return retVal;

        }
        if ((device.getRequestedDeviceType() == null || DeviceType.isStorage(device.getRequestedDeviceType()))
                && StringUtils.isNotEmpty(device.getStorageCredentialId())) {
            retVal = checkEql(device.getIpAddress(), device);
            if (retVal != DiscoverDeviceType.UNKNOWN)
                return retVal;

            retVal = checkCompllent(device.getIpAddress(), device);
            if (retVal != DiscoverDeviceType.UNKNOWN)
                return retVal;
            retVal = checkEmcVnx(device.getIpAddress(), device);

            if (retVal != DiscoverDeviceType.UNKNOWN)
                return retVal;

            retVal = checkNetApp(device.getIpAddress(), device);
            if (retVal != DiscoverDeviceType.UNKNOWN)
                return retVal;

        }
        if ((device.getRequestedDeviceType() == null || DeviceType.isVcenter(device.getRequestedDeviceType()))
                && StringUtils.isNotEmpty(device.getvCenterCredentialId())) {
            retVal = checkVCenter(device.getIpAddress(), device);
            if (retVal != DiscoverDeviceType.UNKNOWN)
                return retVal;

        }
        if ((device.getRequestedDeviceType() == null || DeviceType.isSCVMM(device.getRequestedDeviceType()))
                && StringUtils.isNotEmpty(device.getScvmmCredentialId())) {
            retVal = checkSCVMM(device.getIpAddress(), device);
            if (retVal != DiscoverDeviceType.UNKNOWN)
                return retVal;

        }
        if ((device.getRequestedDeviceType() == null || DeviceType.em == device.getRequestedDeviceType())
                && StringUtils.isNotEmpty(device.getEmCredentialId())) {
            retVal = checkEM(device.getIpAddress(), device);
            if (retVal != DiscoverDeviceType.UNKNOWN)
                return retVal;
        }

        return retVal;
    }

    private static DiscoverDeviceType checkBrocade(String ipAddress, InfrastructureDevice device) {
        String html = String.format("http://%s/switchExplorer_installed.html", ipAddress);
        DiscoverDeviceType retVal = DiscoverDeviceType.UNKNOWN;

        try {
            String response = getHTML(html);
            device.setDiscoveryResponse(response);
            LOGGER.debug("In DeviceTypeCheck.checkBrocade84IOM " + response);
            if (response.contains("M5424") || response.contains("_FC_IOM")) {
                retVal = DiscoverDeviceType.DELL_IOM_84;
            } else if (response.contains("com.brocade.web.switchview.SwitchExplorerApplet")) {
                retVal = DiscoverDeviceType.BROCADE;
            }
        } catch (IOException ioe) {
            LOGGER.debug("In DeviceTypeCheck.checkBrocade84IOM, could not connect to " + ipAddress + " because of "
                    + ioe.getMessage() + ".  Ignoring.");
        }
        return retVal;
    }

    /**
     * Creates an SSH session to the given server on a custom TCP port
     * using the provided credentials.  This is equivalent to Expect's
     * <code>spawn ssh $hostname</code>.
     *
     * This method is essentially the same as ExpectUtils.SSH, but it
     * properly disconnects the ssh session. ExpectUtils.SSH is buggy
     * and leaves the ssh connection open. <b>Do not use ExpectUtils.SSH!</b>
     *
     * @param hostname the DNS or IP address of the remote server
     * @param username the account name to use when authenticating
     * @param password the account password to use when authenticating
     * @return the controlling Expect4j instance
     * @throws Exception on a variety of errors
     */
    private static Expect4j ssh(String hostname, String username, String password) throws Exception {
        final int port = 22;
        LOGGER.debug("Creating SSH session with " + hostname + ":" + port + " as " + username);

        JSch jsch = new JSch();
        final Session session = jsch.getSession(username, hostname, port);
        if (password != null) {
            LOGGER.trace("Setting the Jsch password to the one provided (not shown)");
            session.setPassword(password);
        }

        Hashtable<String, String> config = new Hashtable<>();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        session.setDaemonThread(true);
        session.connect(3 * 1000); // making a connection with timeout.

        ChannelShell channel = (ChannelShell) session.openChannel("shell");
        channel.setPtyType("vt102");

        Expect4j expect = new Expect4j(channel.getInputStream(), channel.getOutputStream()) {
            @Override
            public void close() {
                super.close();
                session.disconnect();
            }
        };

        channel.connect(5 * 1000);

        return expect;
    }

    private static DiscoverDeviceType checkForce10(String ipAddress, InfrastructureDevice device) {
        Expect4j ssh = null;
        DiscoverDeviceType retVal = DiscoverDeviceType.UNKNOWN;
        CredentialEntity cred = getCredentialDAO().findById(device.getSwitchCredentiallId());

        try {
            Closure closure = new Closure() {
                StringBuffer buffer = new StringBuffer();

                @Override
                public void run(ExpectState expectState) throws Exception {
                    LOGGER.debug("Forec10 SSH output: " + expectState.getBuffer());
                    buffer.append(expectState.getBuffer());
                }

                @Override
                public String toString() {
                    return buffer.toString();
                }
            };

            ssh = ssh(ipAddress, cred.getUsername(), cred.getPasswordData().getString());

            // wait for prompt
            if (ssh.expect("#") == 0) {
                // send version command
                ssh.send("show version\n");

                List<Match> f10Pattern = new ArrayList<Match>();
                Match mat = new RegExpMatch("(Dell Force10|Dell Real Time Operating System Software)", closure);
                f10Pattern.add(mat);

                List<Match> iomPattern = new ArrayList<Match>();
                Match mat2 = new RegExpMatch("(I/O-Aggregator|MXL)", closure);
                iomPattern.add(mat2);

                List<Match> fxPattern = new ArrayList<Match>();
                Match mat3 = new RegExpMatch("IOA|PE-FN", closure);
                fxPattern.add(mat3);

                List<Match> s4810Pattern = new ArrayList<Match>();
                Match mat4 = new RegExpMatch("S4810|S4820", closure);
                s4810Pattern.add(mat4);

                List<Match> s5000Pattern = new ArrayList<Match>();
                Match mat5 = new RegExpMatch("S5000", closure);
                s5000Pattern.add(mat5);

                List<Match> s6000Pattern = new ArrayList<Match>();
                Match mat6 = new RegExpMatch("S6000", closure);
                s6000Pattern.add(mat6);

                List<Match> s4048Pattern = new ArrayList<Match>();
                Match mat7 = new RegExpMatch("S4048", closure);
                s4048Pattern.add(mat7);

                int ret = ssh.expect(f10Pattern);
                if (ret >= 0) {
                    retVal = DiscoverDeviceType.FORCE10;
                    // we have Force10. Multiple types are recognized
                    if (ssh.expect(iomPattern) >= 0) {
                        retVal = DiscoverDeviceType.FORCE10IOM;
                    } else if (ssh.expect(fxPattern) >= 0) {
                        retVal = DiscoverDeviceType.FX2_IOM;
                    } else if (ssh.expect(s4810Pattern) >= 0) {
                        retVal = DiscoverDeviceType.FORCE10_S4810;
                    } else if (ssh.expect(s5000Pattern) >= 0) {
                        retVal = DiscoverDeviceType.FORCE10_S5000;
                    } else if (ssh.expect(s6000Pattern) >= 0) {
                        retVal = DiscoverDeviceType.FORCE10_S6000;
                    } else if (ssh.expect(s4048Pattern) >= 0) {
                        retVal = DiscoverDeviceType.FORCE10_S4048;
                    }
                } else {
                    LOGGER.debug("Unsuccessful check for Force10 pattern, error code: " + expect4jError(ret));
                }
            }
            device.setDiscoveryResponse(closure.toString());
        } catch (Exception e) {
            LOGGER.debug("In DeviceTypeCheck.checkForce10, could not connect to " + ipAddress + " because of "
                    + e.getMessage() + ".  Ignoring.");
        } finally {
            if (ssh != null) {
                try {
                    ssh.send("exit\n");
                } catch (IOException e) {
                    LOGGER.warn("Could not cleanly close ssh connection");
                }
                ssh.close();
            }
        }

        return retVal;
    }

    private static String expect4jError(int ret) {
        switch (ret) {
        case -4:
            return "RET_TRIED_ONCE";
        case -3:
            return "RET_EOF";
        case -2:
            return "RET_TIMEOUT";
        case -1:
            return "RET_UNKNOWN";
        default:
            return String.valueOf(ret);
        }
    }

    /**
     * @param ipAddress
     * @return
     */

    private static DiscoverDeviceType checkCiscoNexus(String ipAddress, InfrastructureDevice device) {
        LOGGER.debug("In DeviceTypeCheck.checkCiscoNexus,  connecting to " + ipAddress);
        Expect4j ssh = null;
        DiscoverDeviceType retVal = DiscoverDeviceType.UNKNOWN;
        CredentialEntity cred = getCredentialDAO().findById(device.getSwitchCredentiallId());

        try {
            Closure closure = new Closure() {
                StringBuffer buffer = new StringBuffer();

                @Override
                public void run(ExpectState expectState) throws Exception {
                    LOGGER.debug("CiscoNexus SSH output: " + expectState.getBuffer());
                    buffer.append(expectState.getBuffer());
                }

                @Override
                public String toString() {
                    return buffer.toString();
                }

            };

            ssh = ssh(ipAddress, cred.getUsername(), cred.getPasswordData().getString());
            ssh.send("show version");

            List<Match> pattern = new ArrayList<Match>();
            Match mat = new RegExpMatch("Cisco Nexus", closure);
            pattern.add(mat);

            if (ssh.expect(pattern) >= 0) {
                retVal = DiscoverDeviceType.CISCONEXUS;
            }
            device.setDiscoveryResponse(closure.toString());
        } catch (Exception e) {
            LOGGER.debug("In DeviceTypeCheck.checkCiscoNexus, could not connect to " + ipAddress + " because of "
                    + e.getMessage() + ".  Ignoring.");
        } finally {
            if (ssh != null) {
                try {
                    ssh.send("exit\n");
                } catch (IOException e) {
                    LOGGER.warn("Could not cleanly close ssh connection");
                }
                ssh.close();
            }
        }
        return retVal;
    }

    private static DiscoverDeviceType checkPowerConnect(String ipAddress, InfrastructureDevice device) {
        Expect4j ssh = null;
        DiscoverDeviceType retVal = DiscoverDeviceType.UNKNOWN;

        // todo we have a mixed model.  TOR is the only ping sweep that requires credential.
        CredentialEntity cred = getCredentialDAO().findById(device.getSwitchCredentiallId());
        try {
            ssh = ssh(ipAddress, cred.getUsername(), cred.getPasswordData().getString());
            Closure closure = new Closure() {
                StringBuffer buffer = new StringBuffer();

                @Override
                public void run(ExpectState expectState) throws Exception {
                    LOGGER.debug("PowerConnect SSH output: " + expectState.getBuffer());
                    buffer.append(expectState.getBuffer());
                }

                @Override
                public String toString() {
                    return buffer.toString();
                }
            };

            // wait for prompt
            if (ssh.expect(">") == 0) {
                // send version command
                ssh.send("show system\n");

                List<Match> patternStart = new ArrayList<Match>();
                Match matStart = new RegExpMatch("Dell Networking", closure);
                patternStart.add(matStart);

                List<Match> pattern2 = new ArrayList<Match>();
                Match mat2 = new RegExpMatch("N3024|N3048", closure);
                pattern2.add(mat2);

                List<Match> pattern3 = new ArrayList<Match>();
                Match mat3 = new RegExpMatch("N4032|N4064|N4032F|N4064F", closure);
                pattern3.add(mat3);

                List<Match> pattern = new ArrayList<Match>();
                Match mat = new RegExpMatch("(PowerConnect|Dell Networking N)", closure);
                pattern.add(mat);

                if (ssh.expect(patternStart) >= 0) {
                    if (ssh.expect(pattern2) >= 0) {
                        retVal = DiscoverDeviceType.POWERCONNECT_N3000;
                    } else if (ssh.expect(pattern3) >= 0) {
                        retVal = DiscoverDeviceType.POWERCONNECT_N4000;
                    } else if (ssh.expect(pattern) >= 0) {
                        retVal = DiscoverDeviceType.POWERCONNECT;
                    }
                }
            }
            device.setDiscoveryResponse(closure.toString());

        } catch (Exception e) {
            LOGGER.debug("In DeviceTypeCheck.POWERCONNECT, could not connect to " + ipAddress + " because of "
                    + e.getMessage() + ".  Ignoring.");
        } finally {
            if (ssh != null) {
                try {
                    ssh.send("exit\n");
                } catch (IOException e) {
                    LOGGER.warn("Could not cleanly close ssh connection");
                }
                ssh.close();
            }
        }
        return retVal;
    }

    private static DiscoverDeviceType checkIdracCmc(String ipAddress, InfrastructureDevice device) {
        String html = String.format("https://%s/cgi-bin/discover", ipAddress);
        DiscoverDeviceType retVal = DiscoverDeviceType.UNKNOWN;

        try {
            String response = getHTML(html);
            device.setDiscoveryResponse(response);
            if (response.contains("<ENDPOINTTYPE>iDRAC7</ENDPOINTTYPE>")) {
                retVal = DiscoverDeviceType.IDRAC7;
            } else if (response.contains("<ENDPOINTTYPE>CMC</ENDPOINTTYPE>")) {
                if (response.contains("<ENDPOINTVER>3.0</ENDPOINTVER>")) {
                    retVal = DiscoverDeviceType.CMC_FX2;
                } else if (response.contains("<ENDPOINTVER>2.0</ENDPOINTVER>")) {
                    retVal = DiscoverDeviceType.UNKNOWN; //blocking discovery of VRTX Chassis per ASM-2635
                } else {
                    retVal = DiscoverDeviceType.CMC;
                }
            } else if (response.contains("<ENDPOINTTYPE>iDRAC8</ENDPOINTTYPE>")) {
                retVal = DiscoverDeviceType.IDRAC8;
            }
        } catch (IOException ioe) {
            LOGGER.debug("In DeviceTypeCheck.checkIdracCmc, could not connect to " + ipAddress + " because of "
                    + ioe.getMessage() + ".  Ignoring.");
        }
        return retVal;
    }

    private static DiscoverDeviceType checkCServer(String ipAddress, InfrastructureDevice device) {
        String html = String.format("https://%s/login.html", ipAddress);
        DiscoverDeviceType retVal = DiscoverDeviceType.UNKNOWN;

        try {
            String response = getHTML(html);
            device.setDiscoveryResponse(response);
            if (response.contains("Dell Remote Management Controller")) {
                retVal = DiscoverDeviceType.CSERVER;
            }
        } catch (IOException ioe) {
            LOGGER.debug("In DeviceTypeCheck.checkCServer, could not connect to " + ipAddress + " because of "
                    + ioe.getMessage() + ".  Ignoring.");
        }
        return retVal;
    }

    private static DiscoverDeviceType checkVCenter(String ipAddress, InfrastructureDevice device) {
        String vcenterHtml = String.format("https://%s/en/welcomeRes.js", ipAddress);
        DiscoverDeviceType retVal = DiscoverDeviceType.UNKNOWN;
        try {
            String vcenterResponse = getHTML(vcenterHtml);
            device.setDiscoveryResponse(vcenterResponse);
            if (vcenterResponse.contains("var ID_VMWVC2 = \"VMware vSphere\";")) {
                retVal = DiscoverDeviceType.VCENTER;
            }
        } catch (IOException ioe) {
            LOGGER.debug("In DeviceTypeCheck.checkVCenter, could not connect to " + ipAddress + " because of "
                    + ioe.getMessage() + ".  Ignoring.");
        }
        return retVal;
    }

    private static DiscoverDeviceType checkEql(String ipAddress, InfrastructureDevice device) {
        CredentialEntity cred = getCredentialDAO().findById(device.getStorageCredentialId());
        if (!(cred instanceof StorageCredentialEntity)) {
            LOGGER.warn("Invalid credential passed for equallogic identification of " + ipAddress + ": " + cred);
            return DiscoverDeviceType.UNKNOWN;
        }
        StorageCredentialEntity storageCred = (StorageCredentialEntity) cred;
        if (StringUtils.isBlank(storageCred.getSnmpCommunityString())) {
            LOGGER.debug(
                    "No snmp community string passed for " + ipAddress + "; skipping equallogic identification");
            return DiscoverDeviceType.UNKNOWN;
        }
        String eqlHtml = String.format("http://%s/groupmgr.html", ipAddress);
        DiscoverDeviceType retVal = DiscoverDeviceType.UNKNOWN;
        try {
            int eqlResponse = httpGet(eqlHtml);
            if (eqlResponse == 200) {
                String eqlManagementIP = getEqualLogicInfo(EQUALLOGIC_MANAGEMENT_IP, ipAddress, storageCred,
                        device);
                if (StringUtils.isBlank(eqlManagementIP)) {
                    // ASM-1018B: if (and only if) no management IP defined, allow Group IP for discovery.
                    eqlManagementIP = getEqualLogicInfo(EQUALLOGIC_GROUP_IP, ipAddress, storageCred, null);
                }
                if (StringUtils.equals(eqlManagementIP, ipAddress)) {
                    retVal = DiscoverDeviceType.EQUALLOGIC;
                } else {
                    retVal = DiscoverDeviceType.EQUALLOGIC_NODISCOVER;
                }
            } else {
                // many other device support HTTP GET, we don't know what is that
                retVal = DiscoverDeviceType.UNKNOWN;
            }
        } catch (IOException ioe) {
            LOGGER.debug("In DeviceTypeCheck.checkEql, could not connect to " + ipAddress + " because of "
                    + ioe.getMessage() + ".  Ignoring.");
        }
        return retVal;
    }

    private static String getEqualLogicInfo(String targetInfoName, String ipAddress, CredentialEntity cred,
            InfrastructureDevice device) {
        ExecuteSystemCommands cmdRunner = ExecuteSystemCommands.getInstance();
        String[] eqlCommand = new String[] { "/bin/bash", "-c",
                "python" + " " + ExecuteSystemCommands.sanitizeShellArgument(PUPPET_EQL_PATH)
                        + "pythonEquallogic.py" + " " + ExecuteSystemCommands.sanitizeShellArgument(ipAddress) + " "
                        + ExecuteSystemCommands.sanitizeShellArgument(cred.getUsername()) + " "
                        + ExecuteSystemCommands.sanitizeShellArgument(cred.getPasswordData().getString()) + " "
                        + "discoverygrpparamsshow | grep" + " "
                        + ExecuteSystemCommands.sanitizeShellArgument(targetInfoName) };
        String result = null;
        try {
            CommandResponse cmdresponse = cmdRunner.runCommandWithConsoleOutput(eqlCommand);
            LOGGER.debug("Return code: " + cmdresponse.getReturnCode() + " Return message: "
                    + cmdresponse.getReturnMessage());
            if (device != null)
                device.setDiscoveryResponse(cmdresponse.getReturnMessage());
            if (cmdresponse.getReturnCode().equalsIgnoreCase("0")) {
                String output = cmdresponse.getReturnMessage();
                Pattern p = Pattern.compile(String.format("%s:(.*)$", targetInfoName));
                Matcher m = p.matcher(output);
                if (m.matches()) {
                    result = m.group(1).trim();
                    LOGGER.info(String.format("getEqualLogicInfo(%s,%s,<credential>): Found match: Result = %s",
                            targetInfoName, ipAddress, result));
                }
            }
        } catch (Exception e) {
            LOGGER.debug("In DeviceTypeCheck.getEqualLogicInfo(), could not connect to " + ipAddress
                    + " because of " + e.getMessage() + ".  Ignoring.");
        }
        return result;
    }

    private static DiscoverDeviceType checkEM(String ipAddress, InfrastructureDevice device) {
        String emHtml = String.format("https://%s:3033/em/EnterpriseManager", ipAddress);
        String loginURL = String.format("https://%s:3033/api/rest/ApiConnection/Login", ipAddress);
        String sResponse = null;
        try {
            sResponse = getHTML(emHtml);
        } catch (IOException ioe) {
            LOGGER.debug("GET html request for " + emHtml + " failed:", ioe);
        }
        try {
            if (sResponse != null
                    && (sResponse.contains("Enterprise Manager") || sResponse.contains("Storage Manager"))) {
                CredentialEntity cred = getCredentialDAO().findById(device.getEmCredentialId());
                String username = StringUtils.isEmpty(cred.getDomain()) ? cred.getUsername()
                        : cred.getDomain() + "\\" + cred.getUsername();
                String response = httpPost(loginURL, username, cred.getPasswordData().getString());

                if (StringUtils.isNotEmpty(response)) {
                    device.setDiscoveryResponse(response);

                    ObjectMapper mapper = new ObjectMapper();
                    Map params = mapper.readValue(response, Map.class);
                    Boolean connected = (Boolean) params.get("connected");
                    if (Boolean.TRUE.equals(connected)) {
                        return DiscoverDeviceType.EM;
                    } else {
                        LOGGER.debug("Login passed but property connected is not true. Response: " + response);
                    }
                }
            }
        } catch (Exception e) {
            LOGGER.debug("POST login request for " + loginURL + " failed:", e);
        }
        return DiscoverDeviceType.UNKNOWN;
    }

    private static DiscoverDeviceType checkCompllent(String ipAddress, InfrastructureDevice device) {
        String compllentHtml = String.format("https://%s/SystemExplorer.asp", ipAddress);
        DiscoverDeviceType retVal = DiscoverDeviceType.UNKNOWN;
        CredentialEntity cred = getCredentialDAO().findById(device.getStorageCredentialId());
        try {
            String compellentResponse = getHTML(compllentHtml);
            if (compellentResponse != null && compellentResponse.toUpperCase().contains("COMPELLENT")) {
                // Ok, we know this device is compellent, but we don't know if it's the master or a slave.
                // Make a compellent api call to get the IP of the master, then compare it to this IP.
                // if they don't match, this is a slave and we want to skip it.

                //                -bash-4.1# java -jar /etc/puppetlabs/puppet/modules/compellent/lib/puppet/files/CompCU-6.3.jar -host 172.17.10.41 -user Admin -password P@ssw0rd -c "system show" -xml xmlfilename
                //                <compellent>
                //                <system>
                //                <SerialNumber>24260</SerialNumber>
                //                <Name>SC8000-10-50</Name>
                //                <ManagementIP>172.17.10.40</ManagementIP>
                //                <Version>6.3.2.16</Version>
                //                <OperationMode>Normal</OperationMode>
                //                <PortsBalanced>No</PortsBalanced>
                //                <MailServer></MailServer>
                //                <BackupMailServer></BackupMailServer>
                //                </system>
                //                </compellent>

                // call compellent command line
                File devicesDir = new File(TEMP_PATH);
                File tempFile = File.createTempFile(ipAddress, ".tmp.conf", devicesDir);
                ExecuteSystemCommands cmdRunner = ExecuteSystemCommands.getInstance();

                String[] volumeCommand = { "java", "-jar",
                        "/etc/puppetlabs/puppet/modules/compellent/lib/puppet/files/CompCU.jar", "-host", ipAddress,
                        "-user", cred.getUsername(), "-password", cred.getPasswordData().getString(), "-c",
                        "system show -xml " + tempFile.getAbsolutePath() };

                //LOGGER.debug("Calling Compellent : " + volumeCommand);
                CommandResponse cmdresponse = cmdRunner.runCommandWithConsoleOutput(volumeCommand);
                LOGGER.debug("Return code: " + cmdresponse.getReturnCode() + " Return message: "
                        + cmdresponse.getReturnMessage());
                device.setDiscoveryResponse(cmdresponse.getReturnMessage());
                if (cmdresponse.getReturnCode().equalsIgnoreCase("0")) {
                    // read the generated XML file, look for managementIP
                    DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
                    DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
                    Document doc = dBuilder.parse(tempFile);

                    NodeList nList = doc.getElementsByTagName("ManagementIP");
                    String reportedManagerIP = null;
                    for (int temp = 0; temp < nList.getLength(); temp++) {

                        Node nNode = nList.item(temp);
                        reportedManagerIP = nNode.getTextContent();
                    }

                    // compare the management ip we found with the one we're discovering
                    if (reportedManagerIP != null && reportedManagerIP.equals(ipAddress)) {
                        retVal = DiscoverDeviceType.COMPELLENT;
                    } else {
                        LOGGER.info("Skipping compellent IP " + ipAddress + " because it is not the management IP, "
                                + reportedManagerIP);
                    }
                }

                try {
                    tempFile.delete();
                } catch (Exception e) {
                    LOGGER.warn("could not delete temp file " + tempFile.getAbsolutePath() + ", ignoring.");
                }
            } else {
                LOGGER.debug("Check for Compellent didn't detect a known pattern in HTML response: "
                        + compellentResponse);
                device.setDiscoveryResponse(compellentResponse);
            }
        } catch (Exception ioe) {
            LOGGER.debug("In DeviceTypeCheck.checkCompllent, could not connect to " + ipAddress + " because of "
                    + ioe.getMessage() + ".  Ignoring.");
        }

        return retVal;
    }

    /**
     * @param ipAddress
     * @return
     */
    private static DiscoverDeviceType checkNetApp(String ipAddress, InfrastructureDevice device) {
        DiscoverDeviceType retVal = DiscoverDeviceType.UNKNOWN;

        CommandResponse cmdresponse;
        ExecuteSystemCommands cmdRunner = ExecuteSystemCommands.getInstance();

        CredentialEntity cred = getCredentialDAO().findById(device.getStorageCredentialId());

        LOGGER.debug("Checking for NetApp using script");
        try {
            String[] cmdAndArgs = { "/opt/puppet/bin/ruby", PUPPET_NETAPP_PATH + "/files/netapp_conn_check.rb",
                    ipAddress, cred.getUsername() };
            Map<String, String> envMap = new HashMap<>();
            envMap.put("PASSWORD", cred.getPassword());
            cmdresponse = cmdRunner.runCommandWithEnvironmentVariables(cmdAndArgs, envMap);
            device.setDiscoveryResponse(cmdresponse.getReturnMessage());
            if (cmdresponse.getReturnCode().equals("0")) {
                retVal = DiscoverDeviceType.NETAPP;
            } else {
                LOGGER.debug("NetApp identification command returned: " + cmdresponse.getReturnMessage());
            }

        } catch (Exception e) {
            LOGGER.debug("In DeviceTypeCheck.checkNetApp, could not connect to " + ipAddress + " because of "
                    + e.getMessage() + ".  Ignoring.");
        }
        return retVal;
    }

    private static DiscoverDeviceType checkSCVMM(String ipAddress, InfrastructureDevice device) {
        DiscoverDeviceType retVal = DiscoverDeviceType.UNKNOWN;

        CommandResponse cmdresponse;
        ExecuteSystemCommands cmdRunner = ExecuteSystemCommands.getInstance();

        CredentialEntity cred = getCredentialDAO().findById(device.getScvmmCredentialId());

        try {
            String userName = (StringUtils.isNotEmpty(cred.getDomain()))
                    ? (cred.getDomain() + "\\" + cred.getUsername())
                    : cred.getUsername();
            String[] cmdAndArgs = { PUPPET_SCVMM_PATH + "/bin/discovery.rb", "--quick", "--server", ipAddress,
                    "--username", userName };
            Map<String, String> envMap = new HashMap<>();
            envMap.put("PASSWORD", cred.getPassword());
            cmdresponse = cmdRunner.runCommandWithEnvironmentVariables(cmdAndArgs, envMap);
            device.setDiscoveryResponse(cmdresponse.getReturnMessage());
            if (cmdresponse.getReturnCode().equals("0")) {
                retVal = DiscoverDeviceType.SCVMM;
            }

        } catch (Exception e) {
            LOGGER.debug("In DeviceTypeCheck.checkSCVMM, could not connect to " + ipAddress + " because of "
                    + e.getMessage() + ".  Ignoring.");
        }
        return retVal;
    }

    // Trust Manager which will NOT do any Cert checking
    static X509TrustManager tmNoCheck = new X509TrustManager() {
        @Override
        public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
        }

        @Override
        public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };

    static HostnameVerifier hv = new HostnameVerifier() {
        @Override
        public boolean verify(String urlHostName, SSLSession session) {
            return true;
        }
    };
    private static CredentialDAO credentialDAO;

    private static CredentialDAO getCredentialDAO() {
        if (null == credentialDAO) {
            credentialDAO = CredentialDAO.getInstance();
        }
        return credentialDAO;
    }

    private static DiscoverDeviceType checkEmcVnx(String ipAddress, InfrastructureDevice device) {
        DiscoverDeviceType retVal = DiscoverDeviceType.UNKNOWN;

        CommandResponse cmdresponse;
        ExecuteSystemCommands cmdRunner = ExecuteSystemCommands.getInstance();

        CredentialEntity cred = getCredentialDAO().findById(device.getStorageCredentialId());

        LOGGER.debug("Checking for EMC VNX using script");
        try {
            String[] cmdAndArgs = { "/opt/puppet/bin/ruby", PUPPET_EMC_VNX_PATH + "/files/emc_vnx_conn_check.rb",
                    ipAddress, cred.getUsername(), cred.getPassword() };
            cmdresponse = cmdRunner.runCommandWithConsoleOutput(cmdAndArgs);
            device.setDiscoveryResponse(cmdresponse.getReturnMessage());
            if (cmdresponse.getReturnCode().equals("0")) {
                retVal = DiscoverDeviceType.VNX;
            } else {
                LOGGER.debug("DeviceType was not EMC VNX.  EMC VNX identification command returned: "
                        + cmdresponse.getReturnMessage());
            }

        } catch (Exception e) {
            LOGGER.debug("In DeviceTypeCheck.checkEmcVnx, could not connect to " + ipAddress + " because of "
                    + e.getMessage() + ".  Ignoring.");
        }
        return retVal;
    }

}