org.hyperic.hq.plugin.vmware.VMwareDetector.java Source code

Java tutorial

Introduction

Here is the source code for org.hyperic.hq.plugin.vmware.VMwareDetector.java

Source

/*
 * NOTE: This copyright does *not* cover user programs that use HQ
 * program services by normal system calls through the application
 * program interfaces provided as part of the Hyperic Plug-in Development
 * Kit or the Hyperic Client Development Kit - this is merely considered
 * normal use of the program, and does *not* fall under the heading of
 * "derived work".
 * 
 * Copyright (C) [2004, 2005, 2006], Hyperic, Inc.
 * This file is part of HQ.
 * 
 * HQ is free software; you can redistribute it and/or modify
 * it under the terms version 2 of the GNU General Public License as
 * published by the Free Software Foundation. This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA.
 */

package org.hyperic.hq.plugin.vmware;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hyperic.hq.product.AutoServerDetector;
import org.hyperic.hq.product.PluginException;
import org.hyperic.hq.product.ProductPlugin;
import org.hyperic.hq.product.ServerDetector;
import org.hyperic.hq.product.ServerResource;
import org.hyperic.hq.product.ServiceResource;

import org.hyperic.util.StringUtil;
import org.hyperic.util.config.ConfigResponse;

import org.hyperic.sigar.win32.RegistryKey;
import org.hyperic.sigar.win32.Win32Exception;

import org.hyperic.sigar.vmware.VM;
import org.hyperic.sigar.vmware.VMControlLibrary;
import org.hyperic.sigar.vmware.VMwareException;
import org.hyperic.sigar.vmware.VMwareServer;

public class VMwareDetector extends ServerDetector implements AutoServerDetector {

    static final String WIN32_EVENTLOG_DIR = "vmserverdRoot\\eventlog\\";

    static final String UNIX_EVENTLOG_DIR = "/var/log/vmware/";

    static final String PROP_VM_CONFIG = "vm.config";
    static final String PROP_VM_DISK = "vm.disk";
    static final String PROP_VM_NIC = "vm.nic";

    static final String VM_NAME = "VM";

    static final String VM_DISK_NAME = "VM Disk";

    static final String VM_NIC_NAME = "VM NIC";

    private static final Log log = LogFactory.getLog(VMwareDetector.class.getName());

    private static String getProductKey(String product) {
        return VMControlLibrary.REGISTRY_ROOT + "\\VMware " + product;
    }

    private static String unquote(String value) {
        if (value.charAt(0) == '"') {
            value = value.substring(1, value.length() - 1);
        }
        return value;
    }

    private static class VMwareProperties extends Properties {

        private VMwareProperties() {
            super();
        }

        public synchronized Object put(Object key, Object value) {
            value = unquote((String) value);
            return super.put(key, value);
        }
    }

    private static Properties loadProperties(File file) {
        Properties props = new VMwareProperties();
        FileInputStream is = null;
        try {
            is = new FileInputStream(file);
            props.load(is);
        } catch (IOException e) {
            log.error("Loading " + file + ": " + e.getMessage(), e);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
        }
        return props;
    }

    private void setCustomProperties(ServerResource server, VMwareProductInfo info) {
        if (info == null) {
            return;
        }
        ConfigResponse cprops = new ConfigResponse();
        cprops.setValue("version", info.release);
        cprops.setValue("build", String.valueOf(info.build));
        setCustomProperties(server, cprops);
    }

    public List getServerResources(ConfigResponse platformConfig) throws PluginException {

        ServerResource server;

        if (!VMControlLibrary.isLoaded()) {
            return null;
        }

        if (isWin32()) {
            server = getWin32Server();
        } else {
            server = getLinuxServer();
        }

        if (server == null) {
            return null;
        }

        ArrayList servers = new ArrayList();
        servers.add(server);
        return servers;
    }

    private boolean isESX() {
        return getTypeInfo().getName().indexOf(VM.ESX) != -1;
    }

    private VMwareProductInfo getProductInfo(Properties props) {
        VMwareProductInfo info;

        try {
            info = VMwareProductInfo.getInfo(props);
        } catch (VMwareException e) {
            log.info("Unable to get VMware product info", e);
            return null;
        }

        if (info == null) {
            log.info("Unable to get VMware product info: " + "User id does not have permission to "
                    + "read VM config files?");
            return null;
        }

        if (!getTypeInfo().getName().equals(info.toString())) {
            return null;
        }

        return info;
    }

    private ServerResource getWin32Server() throws PluginException {

        Properties props = new Properties();
        props.setProperty(VMwareConnectParams.PROP_AUTHD_PORT, VMwareConnectParams.DEFAULT_AUTHD_PORT);

        VMwareProductInfo info = getProductInfo(props);
        if (info == null) {
            return null;
        }

        String[] products = { "GSX Server", "Server" };
        String path = null;

        for (int i = 0; i < products.length; i++) {
            RegistryKey key = null;
            try {
                key = RegistryKey.LocalMachine.openSubKey(getProductKey(products[i]));
                path = key.getStringValue("InstallPath").trim();
                break;
            } catch (Win32Exception e) {
                continue;
            } finally {
                if (key != null) {
                    key.close();
                }
            }
        }

        if (path == null) {
            return null;
        }

        ServerResource server = createServerResource(path);
        server.setProductConfig(new ConfigResponse(props));
        server.setMeasurementConfig();
        setCustomProperties(server, info);
        return server;
    }

    private ServerResource getLinuxServer() throws PluginException {

        File config = new File("/etc/vmware/config");
        if (!config.exists()) {
            return null;
        }

        Properties props = loadProperties(config);

        String path = props.getProperty("defaultVMPath");

        String port = props.getProperty(VMwareConnectParams.PROP_AUTHD_PORT);
        if (port == null) {
            //this is vmware workstation
            return null;
        }

        props.clear();

        VMwareProductInfo info = getProductInfo(props);
        if (info == null) {
            return null;
        }
        if (isESX()) {
            if ((info.major == 3) && (info.minor > 0)) {
                //only 3.0.x and lower are supported
                log.warn(info.version + " not supported, see: "
                        + "http://support.hyperic.com/display/hypcomm/VMware");
                return null;
            }
        }

        if (path == null) {
            path = "/etc/vmware";
        }

        ServerResource server = createServerResource(path);
        server.setProductConfig(new ConfigResponse(props));
        server.setMeasurementConfig();
        setCustomProperties(server, info);
        return server;
    }

    static List getDisks(VM vm) throws VMwareException {
        List disks = new ArrayList();
        String diskRes = VMwareMetrics.getResource(vm, "disk.HTL");
        StringTokenizer tok = new StringTokenizer(diskRes, ",");

        while (tok.hasMoreTokens()) {
            disks.add(tok.nextToken());
        }

        return disks;
    }

    static List getNICs(VM vm) throws VMwareException {
        List nics = new ArrayList();
        String nicRes = VMwareMetrics.getResource(vm, "net.adapters");
        StringTokenizer tok = new StringTokenizer(nicRes, ",");

        while (tok.hasMoreTokens()) {
            nics.add(tok.nextToken());
        }

        return nics;
    }

    private String serviceName(String vmName, String type) {
        return vmName + " " + type;
    }

    private String serviceName(String vmName, String type, String name) {
        return serviceName(vmName, type) + " (" + name + ")";
    }

    private void discoverDisks(VM vm, List services, String vmName, String vmConfig) throws VMwareException {

        List disks = getDisks(vm);

        for (int i = 0; i < disks.size(); i++) {
            String disk = (String) disks.get(i);

            ServiceResource service = new ServiceResource();
            service.setType(this, VM_DISK_NAME);
            service.setServiceName(serviceName(vmName, VM_DISK_NAME, disk));

            ConfigResponse config = new ConfigResponse();
            config.setValue(PROP_VM_CONFIG, vmConfig);
            config.setValue(PROP_VM_DISK, disk);
            service.setProductConfig(config);
            service.setMeasurementConfig();

            services.add(service);
        }
    }

    private void discoverNICs(VM vm, List services, String vmName, String vmConfig) throws VMwareException {

        List nics = getNICs(vm);

        for (int i = 0; i < nics.size(); i++) {
            String nic = (String) nics.get(i);

            ServiceResource service = new ServiceResource();
            service.setType(this, VM_NIC_NAME);
            service.setServiceName(serviceName(vmName, VM_NIC_NAME, nic));

            ConfigResponse config = new ConfigResponse();
            config.setValue(PROP_VM_CONFIG, vmConfig);
            config.setValue(PROP_VM_NIC, nic);
            service.setProductConfig(config);
            service.setMeasurementConfig();

            services.add(service);
        }
    }

    private void getGuestProps(VM vm, ConfigResponse cprops) {
        try {
            cprops.setValue("ip", vm.getGuestInfo("ip"));
        } catch (VMwareException e) {
        }
    }

    //pass these vars to the guest OS where plugin on the
    //otherside can link back to the host
    private void setGuestInfo(String name, VM vm, ConfigResponse config) {
        String[] props = { ProductPlugin.PROP_PLATFORM_ID, //not present w/ PluginDumper
                ProductPlugin.PROP_PLATFORM_NAME, ProductPlugin.PROP_PLATFORM_FQDN,
                ProductPlugin.PROP_PLATFORM_IP, };

        for (int i = 0; i < props.length; i++) {
            String key = props[i];
            String val = config.getValue(key);

            String gkey = "hq." + key;
            //log.debug(name + ": guestinfo." + gkey + "=" + val);

            if (val == null) {
                //dont want PluginDumper to set the rest
                return;
            }
            //XXX works as root, would be good
            //to figure out howto set perms for another user
            try {
                vm.setGuestInfo(gkey, val);
            } catch (VMwareException e) {
                String msg = "Cannot link guest to host: " + e.getMessage();
                log.info(msg);
                break; //will be permission denied
            }
        }
    }

    protected List discoverServices(ConfigResponse serverConfig) throws PluginException {

        synchronized (VMwareConnectParams.LOCK) {
            return getServices(serverConfig);
        }
    }

    private String vmLogName(String name) {
        String encoded = URLEncoder.encode(name);
        return StringUtil.replace(encoded, "+", "%20");
    }

    private List getServices(ConfigResponse serverConfig, VM vm, String name) throws VMwareException {

        List services = new ArrayList();

        int state = vm.getExecutionState();
        String displayName = vm.getDisplayName();

        ServiceResource service = new ServiceResource();
        service.setType(this, VM_NAME);
        service.setServiceName(serviceName(displayName, VM_NAME));

        ConfigResponse config = new ConfigResponse();
        config.setValue(PROP_VM_CONFIG, name);

        String logdir = isWin32() ? WIN32_EVENTLOG_DIR : UNIX_EVENTLOG_DIR;
        String logfile = logdir + "event-" + vmLogName(name) + ".log";
        config.setValue(VMwareEventLogPlugin.PROP_FILES_SERVICE, logfile);

        config.setValue(VMwareConfigTrackPlugin.PROP_FILES_SERVICE, name);

        service.setProductConfig(config);

        log.debug(displayName + "=" + VM.EXECUTION_STATES[state]);

        ConfigResponse cprops = new ConfigResponse();

        String[] keys = getCustomPropertiesSchema(service.getType()).getOptionNames();

        //XXX use VM.getConfig if remote
        Properties props = loadProperties(new File(name));
        for (int k = 0; k < keys.length; k++) {
            String value = props.getProperty(keys[k]);
            if (value != null) {
                cprops.setValue(keys[k], value);
            }
        }

        if (state == VM.EXECUTION_STATE_ON) {
            service.setMeasurementConfig();

            if (isESX()) {
                try {
                    discoverDisks(vm, services, displayName, name);
                } catch (VMwareException e) {
                    //XXX 3.0.0 bug disk.HTL not defined
                    log.error("Failed to discover VM Disks: " + e);
                }
                discoverNICs(vm, services, displayName, name);
            }

            getGuestProps(vm, cprops);

            setGuestInfo(displayName, vm, serverConfig);
        }

        service.setCustomProperties(cprops);
        service.setControlConfig();

        services.add(service);

        return services;
    }

    private List getServices(ConfigResponse serverConfig) throws PluginException {

        List services = new ArrayList();
        boolean isServerConnected = false;
        VMwareConnectParams params = new VMwareConnectParams(serverConfig.toProperties());
        VMwareServer server = new VMwareServer();

        try {
            server.connect(params);
            isServerConnected = true;

            List names = server.getRegisteredVmNames();
            log.debug("Found " + names.size() + " registered VMs");

            for (int i = 0; i < names.size(); i++) {
                String name = (String) names.get(i);
                VM vm = new VM();
                boolean isVmConnected = false;
                try {
                    vm.connect(params, name);
                    isVmConnected = true;
                    services.addAll(getServices(serverConfig, vm, name));
                } catch (VMwareException e) {
                    log.error("Error discovering " + name + " services: " + e.getMessage(), e);
                } finally {
                    if (isVmConnected) {
                        vm.disconnect();
                    }
                    vm.dispose();
                }
            }
        } catch (VMwareException e) {
            throw new PluginException("Error discovering VMs: " + e.getMessage(), e);
        } finally {
            params.dispose();

            if (isServerConnected) {
                server.disconnect();
            }
            server.dispose();
        }

        return services;
    }
}