io.macgyver.plugin.cloud.vsphere.VSphereScanner.java Source code

Java tutorial

Introduction

Here is the source code for io.macgyver.plugin.cloud.vsphere.VSphereScanner.java

Source

/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.macgyver.plugin.cloud.vsphere;

import io.macgyver.neorx.rest.NeoRxClient;

import java.rmi.RemoteException;
import java.util.Iterator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.common.hash.Hashing;
import com.vmware.vim25.GuestInfo;
import com.vmware.vim25.HostHardwareInfo;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.VirtualMachineConfigInfo;
import com.vmware.vim25.mo.HostSystem;
import com.vmware.vim25.mo.ServerConnection;
import com.vmware.vim25.mo.ServiceInstance;
import com.vmware.vim25.mo.VirtualMachine;

public class VSphereScanner {

    ObjectMapper mapper = new ObjectMapper();
    Logger logger = LoggerFactory.getLogger(VSphereScanner.class);

    ServiceInstance serviceInstance;
    NeoRxClient client;
    String vcenterUuid;

    protected VSphereScanner() {
        // for unit testing
    }

    public VSphereScanner(ServiceInstance si, NeoRxClient client) {

        Preconditions.checkNotNull(si);
        Preconditions.checkNotNull(client);
        serviceInstance = si;
        this.client = client;
    }

    protected JsonNode ensureController() {
        String cypher = "merge (c:ComputeController {macId: {macId}}) set c.type='vcenter' return c";
        return client.execCypher(cypher, "macId", getVCenterId()).toBlocking().first();
    }

    public synchronized String getVCenterId() {
        if (vcenterUuid == null) {
            vcenterUuid = serviceInstance.getAboutInfo().getInstanceUuid();
        }
        return vcenterUuid;
    }

    private void setVal(ObjectNode n, String prop, String val) {
        n.put(prop, val);
    }

    public String createSetClause(String alias, JsonNode n) {
        StringBuffer sb = new StringBuffer();
        Iterator<String> t = n.fieldNames();
        int i = 0;
        while (t.hasNext()) {
            String key = t.next();

            sb.append(String.format("%s %s.%s={%s} ", (i > 0) ? "," : "", alias, key, key));
            i++;
        }
        return sb.toString();
    }

    public void updateComputeHost(ObjectNode n) {
        String setClause = createSetClause("c", n);

        String cypher = String.format(
                "merge (c:ComputeHost {macId:{macId}}) on match set %s ,c.updateTs=timestamp() ON CREATE SET %s, c.updateTs=timestamp() return c",
                setClause, setClause);

        JsonNode computeHost = client.execCypher(cypher, n).toBlocking().first();

        JsonNode vcenter = ensureController();

        String vcenterMacId = vcenter.get("macId").asText();
        cypher = "match (c:ComputeController {macId:{vcenterMacId}}), (h:ComputeHost {macId:{hostMacId} }) MERGE (c)-[r:MANAGES]->(h) ON CREATE SET r.updateTs=timestamp() ON MATCH SET r.updateTs=timestamp() return r";
        client.execCypher(cypher, "vcenterMacId", vcenterMacId, "hostMacId", computeHost.get("macId").asText());
    }

    public void updateComputeInstance(ObjectNode n) {

        String setClause = createSetClause("c", n);

        String cypher = "merge (c:ComputeInstance {macId:{macId}}) on match set " + setClause
                + ",c.updateTs=timestamp() ON CREATE SET " + setClause + ", c.updateTs=timestamp() return c";

        client.execCypher(cypher, n).toBlocking().first();

    }

    String getMacUuid(VirtualMachine vm) {
        return vm.getConfig().getInstanceUuid();
    }

    public String computeMacId(ManagedObjectReference mor) {
        Preconditions.checkNotNull(mor, "ManagedObjectReference cannot be null");

        Preconditions.checkArgument(!ManagedObjectTypes.VIRTUAL_MACHINE.equals(mor.getType()),
                "cannot call computeMacId() with mor.type=VirtualMachine");

        return Hashing.sha1().hashString(getVCenterId() + mor.getType() + mor.getVal(), Charsets.UTF_8).toString();
    }

    ObjectNode toComputeNodeData(VirtualMachine vm) {
        ObjectNode n = mapper.createObjectNode();
        try {
            VirtualMachineConfigInfo cfg = vm.getConfig();

            // http://www.virtuallyghetto.com/2011/11/vsphere-moref-managed-object-reference.html

            ServerConnection sc = vm.getServerConnection();

            ManagedObjectReference mor = vm.getMOR();
            String moType = mor.getType();
            String moVal = mor.getVal();
            GuestInfo g = vm.getGuest();
            setVal(n, "name", vm.getName());
            setVal(n, "macId", getMacUuid(vm));
            setVal(n, "vmw_instanceUuid", cfg.getInstanceUuid());
            setVal(n, "vmw_morVal", moVal);
            setVal(n, "vmw_morType", moType);
            setVal(n, "vmw_annotation", cfg.getAnnotation());
            setVal(n, "vmw_guestToolsVersion", g.getToolsVersion());
            setVal(n, "vmw_guestId", g.getGuestId());
            setVal(n, "vmw_guestFamily", g.getGuestFamily());
            setVal(n, "vmw_guestFullName", g.getGuestFullName());
            setVal(n, "vmw_guestIpAddress", g.getIpAddress());
            setVal(n, "vmw_guestId", g.getGuestId());
            setVal(n, "vmw_guestHostName", g.getHostName());
            setVal(n, "vmw_guestAlternateName", cfg.getAlternateGuestName());
            setVal(n, "vmw_locationId", cfg.getLocationId());
            setVal(n, "vmw_numCPU", "" + cfg.getHardware().getMemoryMB());
            setVal(n, "vmw_memoryMB", "" + cfg.getHardware().getNumCPU());

        } catch (Exception e) {
            logger.warn("", e);
        }
        return n;
    }

    public void scan(VirtualMachine vm) {
        logger.debug("scanning vm: {}", vm.getName());
        ObjectNode n = toComputeNodeData(vm);
        updateComputeInstance(n);
    }

    ObjectNode toObjectNode(HostSystem host) {
        ManagedObjectReference mor = host.getMOR();
        HostHardwareInfo hh = host.getHardware();
        ObjectNode n = mapper.createObjectNode().put("macId", getMacId(host)).put("name", host.getName())
                .put("vmw_morType", mor.getType()).put("vmw_morVal", mor.getVal()).put("vmw_hardwareModel",

                        hh.getSystemInfo().getModel())
                .put("vmw_cpuCoreCount", hh.getCpuInfo().getNumCpuCores())
                .put("vmw_memorySize", hh.getMemorySize());

        return n;
    }

    public void updateHostVmRelationship(HostSystem h, VirtualMachine vm) {

        logger.debug("updating relationship between host={} and vm={}", h.getName(), vm.getName());
        String cypher = "match (h:ComputeHost {macId:{hostMacUuid} }), (c:ComputeInstance {macId: {computeMacUuid}}) MERGE (h)-[r:HOSTS]->(c) ON CREATE SET r.updateTs=timestamp(),r.createTs=timestamp() ON MATCH SET r.updateTs=timestamp() return r";
        client.execCypher(cypher, "hostMacUuid", getMacId(h), "computeMacUuid", getMacUuid(vm));

        // This might be a better place to remove any *other* rlationships from
        // VM->Host

    }

    public void scanHost(HostSystem host) {
        try {
            logger.info("scanning esxi host {} and vms hosted on it", host.getName());
            ObjectNode n = toObjectNode(host);

            updateComputeHost(n);

            long now = client.execCypher("return timestamp() as ts").toBlocking().first().asLong();

            VirtualMachine[] vms = host.getVms();
            if (vms != null) {
                for (VirtualMachine vm : vms) {
                    try {
                        scan(vm);
                    } catch (RuntimeException e) {
                        logger.warn("", e);
                    }

                    // Use a separate try/catch for the relationships so that if
                    // something went wrong above, we still get the
                    // relationships right.
                    try {
                        updateHostVmRelationship(host, vm);
                    } catch (RuntimeException e) {
                        logger.warn("", e);
                    }
                }
            }

            clearStaleRelationships(host, now);
        } catch (RemoteException e) {
            throw new VSphereExceptionWrapper(e);
        }

    }

    protected String getMacId(HostSystem h) {
        return computeMacId(h.getMOR());

    }

    protected void clearStaleRelationships(HostSystem host, long ts) {
        logger.info("clearing stale ComputeHost->ComputeInstance relationships for host: {}", host.getName());
        String cypher = "match (h:ComputeHost {macId:{macId}})-[r:HOSTS]-(c:ComputeInstance) where r.updateTs<{ts} delete r";

        // this is for logging only

        for (JsonNode n : client
                .execCypher(cypher.replace("delete r", "return r"), "macId", getMacId(host), "ts", ts).toBlocking()
                .toIterable()) {
            logger.info("clearing stale relationship: {}", n);
        }
        // end of logging section

        client.execCypher(cypher, "macId", getMacId(host), "ts", ts);
    }

    public void scanAllHosts() {
        VSphereQueryTemplate t = new VSphereQueryTemplate(serviceInstance);
        for (HostSystem host : t.findAllHostSystems()) {

            try {

                scanHost(host);

            } catch (RuntimeException e) {
                logger.warn("scan host failed: {}", host.getName());
            }

        }
    }

}