werecloud.api.bean.VMWareMacCache.java Source code

Java tutorial

Introduction

Here is the source code for werecloud.api.bean.VMWareMacCache.java

Source

/*
  werecloud provides a simple API to the VMWare vCenter data.
  Copyright (C) 2015  NigelB
    
  This program 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 2
  of the License, or (at your option) any later version.
    
  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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package werecloud.api.bean;

import com.vmware.vim25.*;
import com.vmware.vim25.mo.*;
import com.vmware.vim25.mo.util.MorUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import werecloud.api.controller.v1_0_0.VirtualMachineController;
import werecloud.api.model.ConnectionModel;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * <code>VMWareMacCache</code>
 * Date: 28/12/2014
 * Time: 1:05 PM
 */
public class VMWareMacCache implements ApplicationListener, Runnable {
    private PropertyFilter propFilter;
    private EventManager _eventManager;
    private Thread updaeThread;
    private Logger logger = LoggerFactory.getLogger(VirtualMachineController.class);

    private Folder rootFolder;
    //    public static Logger
    private ServiceInstance si = null;
    private ConnectionModel conn;
    private EventHistoryCollector collector;
    private int loadThreads;

    private Hashtable<String, String> macAddresses = new Hashtable<String, String>();
    private Hashtable<String, String> vmIDMap = new Hashtable<String, String>();
    private PropertyCollector propColl;
    private EventHistoryCollector _eventHistoryCollector;

    private volatile boolean running = true;

    public VMWareMacCache(ConnectionModel connection, int loadThreads)
            throws MalformedURLException, RemoteException {
        System.out.println(connection);
        System.out.println(loadThreads);
        this.conn = connection;
        this.loadThreads = loadThreads;

        try {
            si = conn.getServiceInstance();
            rootFolder = si.getRootFolder();
            initializeMACCache();
        } catch (RemoteException e) {
            si = null;
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        try {
            _eventManager = si.getEventManager();
            createEventHistoryCollector();

            PropertyFilterSpec eventFilterSpec = createEventFilterSpec();
            propColl = si.getPropertyCollector();

            propFilter = propColl.createFilter(eventFilterSpec, true);
            updaeThread = new Thread(this);
            updaeThread.start();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    private void createEventHistoryCollector() throws Exception {
        // Create an Entity Event Filter Spec to
        // specify the MoRef of the VM to be get events filtered for
        EventFilterSpecByEntity entitySpec = new EventFilterSpecByEntity();
        entitySpec.setEntity(rootFolder.getMOR());
        entitySpec.setRecursion(EventFilterSpecRecursionOption.children);

        // set the entity spec in the EventFilter
        EventFilterSpec eventFilter = new EventFilterSpec();
        eventFilter.setEntity(entitySpec);

        // we are only interested in getting events for the VM.
        // Add as many events you want to track relating to vm.
        // Refer to API Data Object vmEvent and see the extends class list for
        // elaborate list of vmEvents
        eventFilter.setType(
                new String[] { "VmReconfiguredEvent", "VmRenamedEvent", "VmCreatedEvent", "VmRemovedEvent" });
        //        eventFilter.setType(new String[] { "VmPoweredOffEvent",
        //                "VmPoweredOnEvent", "VmSuspendedEvent", "VmRenamedEvent" });

        // create the EventHistoryCollector to monitor events for a VM
        // and get the ManagedObjectReference of the EventHistoryCollector
        // returned
        _eventHistoryCollector = _eventManager.createCollectorForEvents(eventFilter);
    }

    private PropertyFilterSpec createEventFilterSpec() {
        // Set up a PropertySpec to use the latestPage attribute
        // of the EventHistoryCollector

        PropertySpec propSpec = new PropertySpec();
        propSpec.setAll(new Boolean(false));
        propSpec.setPathSet(new String[] { "latestPage" });
        propSpec.setType(_eventHistoryCollector.getMOR().getType());

        // PropertySpecs are wrapped in a PropertySpec array
        PropertySpec[] propSpecAry = new PropertySpec[] { propSpec };

        // Set up an ObjectSpec with the above PropertySpec for the
        // EventHistoryCollector we just created
        // as the Root or Starting Object to get Attributes for.
        ObjectSpec objSpec = new ObjectSpec();
        objSpec.setObj(_eventHistoryCollector.getMOR());
        objSpec.setSkip(new Boolean(false));

        // Get Event objects in "latestPage" from "EventHistoryCollector"
        // and no "traversl" further, so, no SelectionSpec is specified
        objSpec.setSelectSet(new SelectionSpec[] {});

        // ObjectSpecs are wrapped in an ObjectSpec array
        ObjectSpec[] objSpecAry = new ObjectSpec[] { objSpec };

        PropertyFilterSpec spec = new PropertyFilterSpec();
        spec.setPropSet(propSpecAry);
        spec.setObjectSet(objSpecAry);
        return spec;
    }

    public String getVM(String mac) {
        logger.info("Requesting name of vm with MAC address: {}, found: {} ", mac.toUpperCase(),
                macAddresses.get(mac.toUpperCase()));
        return macAddresses.get(mac.toUpperCase());
    }

    private void initializeMACCache() throws RemoteException, InterruptedException {
        long start = System.currentTimeMillis();
        ManagedEntity[] mes = new InventoryNavigator(rootFolder).searchManagedEntities("VirtualMachine");
        ExecutorService exec = Executors.newFixedThreadPool(loadThreads);
        try {
            for (final ManagedEntity me : mes) {
                exec.submit(new Runnable() {
                    @Override
                    public void run() {
                        VirtualMachine vm = (VirtualMachine) me;
                        addVirtualMachine(vm);
                    }
                });
            }
        } finally {
            exec.shutdown();
        }
        exec.awaitTermination(1, TimeUnit.HOURS);
        logger.info("{} MAC addresses added and took {} milliseconds.", macAddresses.size(),
                System.currentTimeMillis() - start);
    }

    private void addVirtualMachine(VirtualMachine vm) {
        vmIDMap.put(vm.getMOR().get_value(), vm.getName());
        VirtualMachineConfigInfo config = vm.getConfig();
        for (VirtualDevice virtualDevice : config.getHardware().getDevice()) {
            if (virtualDevice instanceof VirtualEthernetCard) {
                macAddresses.put(((VirtualEthernetCard) virtualDevice).getMacAddress().toUpperCase(), vm.getName());
                logger.debug("Adding MAC {} for vm {}",
                        ((VirtualEthernetCard) virtualDevice).getMacAddress().toUpperCase(), vm.getName());
            }
        }
    }

    private void removeVMByName(String name) {
        ArrayList<String> toRemove = new ArrayList<String>();
        for (Map.Entry<String, String> macEntry : macAddresses.entrySet()) {
            if (macEntry.getValue().equals(name)) {
                toRemove.add(macEntry.getKey());
            }
        }
        for (String invalidMACAddress : toRemove) {
            macAddresses.remove(invalidMACAddress);
            logger.trace(String.format("Removing MAC address: %s for %s", invalidMACAddress, name));
        }
        for (Map.Entry<String, String> stringStringEntry : vmIDMap.entrySet()) {
            if (stringStringEntry.getValue().equals(name)) {
                vmIDMap.remove(stringStringEntry.getValue());
                logger.trace("Removed " + stringStringEntry.getKey() + " -> " + stringStringEntry.getValue()
                        + " from vmIDMap");
            }
        }
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        try {
            Method m = this.getClass().getMethod("handle", event.getClass());
            m.invoke(this, event);
            return;
        } catch (NoSuchMethodException nme) {
            logger.trace(String.format("Unhandled event: %s", event));
        } catch (Exception e) {
            logger.error("Error: ", e);
        }
        //        logger.trace(event.toString());
    }

    public void handle(ContextRefreshedEvent event) {
        System.out.println(event);
    }

    public void handle() {

    }

    private void handleUpdate(UpdateSet update) {
        ObjectUpdate[] vmUpdates;
        PropertyFilterUpdate[] pfus = update.getFilterSet();
        for (int pfui = 0; pfui < pfus.length; pfui++) {
            //            System.out.println("Virtual Machine updates:");
            vmUpdates = pfus[pfui].getObjectSet();
            for (ObjectUpdate vmi : vmUpdates) {
                //                System.out.println("Handling object update");
                handleObjectUpdate(vmi);
            }
        }
    }

    void handleObjectUpdate(ObjectUpdate oUpdate) {
        PropertyChange[] pc = oUpdate.getChangeSet();
        //        System.out.println("Update kind = " + oUpdate.getKind());
        if (oUpdate.getKind() == ObjectUpdateKind.enter) {
            //            System.out.println(" New Data:");
            handleChanges(pc);
        } else if (oUpdate.getKind() == ObjectUpdateKind.leave) {
            //            System.out.println(" Removed Data:");
            handleChanges(pc);
        } else if (oUpdate.getKind() == ObjectUpdateKind.modify) {
            //            System.out.println(" Changed Data:");
            handleChanges(pc);
        }

    }

    synchronized void handleChanges(PropertyChange[] changes) {
        for (int pci = 0; pci < changes.length; ++pci) {
            String name = changes[pci].getName();
            Object value = changes[pci].getVal();
            PropertyChangeOp op = changes[pci].getOp();
            if (value != null && op != PropertyChangeOp.remove) {
                //                logger.debug(String.format("Unhandled: %s", value));
                /*                System.out.println("===============");
                                System.out.println("\nEvent Details follows:");
                                if (value instanceof ArrayOfEvent) {
                ArrayOfEvent aoe = (ArrayOfEvent) value;
                Event[] evts = aoe.getEvent();
                for (int evtID = 0; evtID < evts.length; ++evtID) {
                    Event anEvent = evts[evtID];
                    System.out.println("\n----------" + "\n Event ID: "
                            + anEvent.getKey() + "\n Event: "
                            + anEvent.getClass().getName()
                            + "\n FullFormattedMessage: "
                            + anEvent.getFullFormattedMessage()
                            + "\n VM Reference: "
                            + anEvent.getVm().getVm().get_value()
                            + "\n----------\n");
                }
                                } else*/
                if (value instanceof VmEvent) {
                    VmEvent anEvent = (VmEvent) value;
                    //                    System.out.println("\n----------" + "\n Event ID: "
                    //                            + anEvent.getKey() + "\n Event: "
                    //                            + anEvent.getClass().getName()
                    //                            + "\n FullFormattedMessage: "
                    //                            + anEvent.getFullFormattedMessage()
                    //                            + "\n VM Reference: "
                    //                            + anEvent.getVm().getVm().get_value()
                    //                            + "\n----------\n");
                    try {
                        logger.trace(anEvent.getClass().toString());
                        Method m = VMWareMacCache.class.getDeclaredMethod("handleEvent", anEvent.getClass());
                        logger.trace(String.format("Event Handler: %s", m));
                        m.invoke(this, anEvent);
                    } catch (NoSuchMethodException e) {
                        logger.debug(String.format("1. Unhandled: %s", anEvent));
                    } catch (InvocationTargetException e) {
                        logger.debug(String.format("2. Unhandled: %s", anEvent));
                    } catch (IllegalAccessException e) {
                        logger.debug(String.format("3. Unhandled: %s", anEvent));
                    }
                }
                //                System.out.println("===============");
            }
        }
    }

    private void handleEvent(VmRenamedEvent renamedEvent) {
        VirtualMachine vm = (VirtualMachine) MorUtil.createExactManagedObject(si.getServerConnection(),
                renamedEvent.getVm().getVm());
        ArrayList<String> toRename = new ArrayList<String>();
        vmIDMap.put(vm.getMOR().get_value(), renamedEvent.getNewName());
        for (Map.Entry<String, String> macEntry : macAddresses.entrySet()) {
            if (macEntry.getValue().equals(renamedEvent.getOldName())) {
                toRename.add(macEntry.getKey());
            }
        }
        for (String mac : toRename) {
            macAddresses.put(mac, renamedEvent.getNewName());
            logger.debug("Renamed " + mac + " to " + renamedEvent.getNewName());
        }
    }

    private void handleEvent(VmReconfiguredEvent vmEvent) {
        VirtualMachine vm = (VirtualMachine) MorUtil.createExactManagedObject(si.getServerConnection(),
                vmEvent.getVm().getVm());
        logger.trace(String.format("%s reconfigured.", vm.getName()));
        String name = vm.getName();
        //        if (vmIDMap.containsKey(vm.getMOR().get_value())) {
        //            name = vmIDMap.get(vm.getMOR().get_value());
        //        }
        removeVMByName(name);
        addVirtualMachine(vm);
    }

    private void handleEvent(VmCreatedEvent vmEvent) {
        VirtualMachine vm = (VirtualMachine) MorUtil.createExactManagedObject(si.getServerConnection(),
                vmEvent.getVm().getVm());
        logger.trace(String.format("Adding Virtual Machine: %s", vm.getName()));
        addVirtualMachine(vm);
    }

    private void handleEvent(VmRemovedEvent vmEvent) {
        logger.trace(String.format("Removing VM %s", vmEvent.getVm().getName()));
        removeVMByName(vmEvent.getVm().getName());
    }

    @Override
    public void run() {
        String version = "";
        while (running) {
            try {
                UpdateSet update = propColl.waitForUpdates(version);
                if (update != null && update.getFilterSet() != null) {

                    version = update.getVersion();
                    logger.info(" Current Version: " + version);
                    handleUpdate(update);

                } else {
                    logger.warn("No update is present!");
                }
            } catch (Throwable e) {
                logger.error(e.getMessage(), e);
            }
        }
    }
}