Package com.vmware.bdd.service.event

Source Code of com.vmware.bdd.service.event.VmEventManager$VcEventWrapper

/***************************************************************************
* Copyright (c) 2014 VMware, Inc. All Rights Reserved.
* 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 com.vmware.bdd.service.event;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.concurrent.BlockingQueue;

import com.vmware.bdd.service.sp.NodePowerOnRequest;

import org.apache.log4j.Logger;

import com.vmware.aurora.exception.AuroraException;
import com.vmware.aurora.global.Configuration;
import com.vmware.aurora.util.CmsWorker;
import com.vmware.aurora.util.CmsWorker.WorkQueue;
import com.vmware.aurora.vc.MoUtil;
import com.vmware.aurora.vc.VcCache;
import com.vmware.aurora.vc.VcHost;
import com.vmware.aurora.vc.VcUtil;
import com.vmware.aurora.vc.VcVirtualMachine;
import com.vmware.aurora.vc.vcevent.VcEventHandlers.IVcEventHandler;
import com.vmware.aurora.vc.vcevent.VcEventHandlers.VcEventType;
import com.vmware.aurora.vc.vcevent.VcEventListener;
import com.vmware.aurora.vc.vcservice.VcContext;
import com.vmware.aurora.vc.vcservice.VcSession;
import com.vmware.bdd.entity.NodeEntity;
import com.vmware.bdd.manager.ClusterManager;
import com.vmware.bdd.manager.SoftwareManagerCollector;
import com.vmware.bdd.manager.intf.IClusterEntityManager;
import com.vmware.bdd.manager.intf.IConcurrentLockedClusterEntityManager;
import com.vmware.bdd.service.utils.VcResourceUtils;
import com.vmware.bdd.utils.AuAssert;
import com.vmware.bdd.utils.CommonUtil;
import com.vmware.bdd.utils.ConfigInfo;
import com.vmware.bdd.utils.Constants;
import com.vmware.vim.binding.vim.Folder;
import com.vmware.vim.binding.vim.event.Event;
import com.vmware.vim.binding.vim.event.EventEx;
import com.vmware.vim.binding.vim.event.HostEvent;
import com.vmware.vim.binding.vim.event.VmEvent;
import com.vmware.vim.binding.vim.vm.FaultToleranceSecondaryConfigInfo;
import com.vmware.vim.binding.vmodl.ManagedObjectReference;
import com.vmware.vim.binding.vmodl.fault.ManagedObjectNotFound;
import static com.vmware.vim.binding.vim.VirtualMachine.PowerState;

public class VmEventManager implements IEventProcessor {

   private static final int WAIT_FOR_VM_STATE_TIMEOUT_SECS = 60;
   private static final int WAIT_FOR_VM_STATE_SLEEP_INTERVAL_SECS = 1;

   public static class VcEventWrapper implements IEventWrapper{
      private VcEventType type;
      private Event event;
      private boolean external;

      public VcEventWrapper(VcEventType type, Event event, boolean external) {
         this.type = type;
         this.event = event;
         this.external = external;
      }

      @Override
      public String getPrimaryKey() {

         if (event instanceof HostEvent) {
            HostEvent he = (HostEvent) event;
            return MoUtil.morefToString(event.getHost().getHost());
         }
         AuAssert.check(event instanceof VmEvent || event instanceof EventEx);
         return MoUtil.morefToString(event.getVm().getVm());
      }

      @Override
      public String toString() {
         return "{moid=" + getPrimaryKey() + ", event=" + type.toString() + "}";
      }
   }

   public static final EnumSet<VcEventType> vmEvents = EnumSet.of(
         VcEventType.VmDasBeingResetWithScreenshot, VcEventType.VmDrsPoweredOn,
         VcEventType.VmMigrated, VcEventType.VmConnected,
         VcEventType.VmCreated, VcEventType.VmDasBeingReset,
         VcEventType.VmDasResetFailed, VcEventType.VmDisconnected,
         VcEventType.VmMessage, VcEventType.VmMessageError,
         VcEventType.VmMessageWarning, VcEventType.VmOrphaned,
         VcEventType.VmPoweredOn, VcEventType.VmPoweredOff,
         VcEventType.VmReconfigured, VcEventType.VmRegistered,
         VcEventType.VmRelocated, VcEventType.VmRemoved, VcEventType.VmRenamed,
         VcEventType.VmResourcePoolMoved, VcEventType.VmResuming,
         VcEventType.VmSuspended, VcEventType.VmAppHealthChanged,
         VcEventType.NotEnoughResourcesToStartVmEvent,
         VcEventType.VmMaxRestartCountReached, VcEventType.VmFailoverFailed,
         VcEventType.VmCloned, VcEventType.VhmError, VcEventType.VhmWarning,
         VcEventType.VhmInfo,
         VcEventType.VhmUser,

         // host event set
         VcEventType.HostConnected, VcEventType.HostRemoved,
         VcEventType.EnteredMaintenanceMode, VcEventType.ExitMaintenanceMode,
         VcEventType.HostDisconnected);

   private static final Logger logger = Logger
         .getLogger(VmEventManager.class);
   private IConcurrentLockedClusterEntityManager lockMgr;
   private IClusterEntityManager clusterEntityMgr;
   private Folder rootSerengetiFolder = null;
   private EventScheduler eventScheduler = null;
   private ClusterManager clusterManager;
   private SoftwareManagerCollector softwareManagerCollector;

   public VmEventManager(IConcurrentLockedClusterEntityManager lockMgr) {
      super();
      this.lockMgr = lockMgr;
      this.clusterEntityMgr = lockMgr.getClusterEntityMgr();
      this.eventScheduler = new EventScheduler(this);
   }

   public void setClusterManager(ClusterManager clusterManager) {
      this.clusterManager = clusterManager;
   }

   public SoftwareManagerCollector getSoftwareManagerCollector() {
      return softwareManagerCollector;
   }

   public void setSoftwareManagerCollector(
         SoftwareManagerCollector softwareManagerCollector) {
      this.softwareManagerCollector = softwareManagerCollector;
   }

   public synchronized void start() {
      this.eventScheduler.start();
   }

   public synchronized void stop() {
      this.eventScheduler.stop();
   }

   private void initRootFolder() {
      String serverMobId =
            Configuration.getString(Constants.SERENGETI_SERVER_VM_MOBID);
      VcVirtualMachine serverVm = VcCache.get(serverMobId);
      String root = ConfigInfo.getSerengetiRootFolder();
      List<String> folderNames = new ArrayList<String>();
      folderNames.add(root);
      this.rootSerengetiFolder =
            VcResourceUtils.findFolderByNameList(serverVm.getDatacenter(),
                  folderNames);
      if (rootSerengetiFolder == null) {
         logger.info("VM root folder" + root
               + " is not created yet. Ignore external VM event.");
      }
   }

   /**
    *
    * @param produceQueue
    */
   @Override
   public void produceEvent(final BlockingQueue<IEventWrapper> produceQueue) {
      VcEventListener.installExtEventHandler(vmEvents, new IVcEventHandler() {
         @Override
         public boolean eventHandler(VcEventType type, Event e)
               throws Exception {
            logger.debug("Received external VM event " + e);
            add(type, e, true, produceQueue);
            return false;
         }
      });
      VcEventListener.installEventHandler(vmEvents, new IVcEventHandler() {
         @Override
         public boolean eventHandler(VcEventType type, Event e)
               throws Exception {
            logger.debug("Received internal VM event " + e);
            add(type, e, false, produceQueue);
            return false;
         }
      });
   }

   private void add(VcEventType type, Event event, boolean external, BlockingQueue<IEventWrapper> produceQueue) {
      VcEventWrapper wrapper = new VcEventWrapper(type, event, external);
      try {
         produceQueue.put(wrapper);
      } catch (InterruptedException e) {
         logger.info("caught " + e);
      }
   }

   @Override
   public void consumeEvent(List<IEventWrapper> toProcessEvents) {
      for (IEventWrapper wrapper : toProcessEvents) {
         final VcEventWrapper eventWrapper = (VcEventWrapper) wrapper;
         Event event = null;
         try {
            if (eventWrapper != null) {
               event = eventWrapper.event;
               VcContext.inVcSessionDo(new VcSession<Void>() {
                  @Override
                  protected boolean isTaskSession() {
                     return true;
                  }

                  @Override
                  protected Void body() throws Exception {
                     processEvent(eventWrapper.type, eventWrapper.event, eventWrapper.external);
                     return null;
                  }
               });
            }
         } catch (Exception e) {
            if (event != null) {
               logger.error("Failed to process event: " + event, e);
            } else {
               logger.error("Failed to process VM event.", e);
            }
         }
      }
   }

   private boolean processExternalEvent(VcEventType type, Event e, String moId)
         throws Exception {
      if (clusterEntityMgr.getNodeByMobId(moId) != null) {
         return true;
      }
      if (type != VcEventType.VmRemoved) {
         VcVirtualMachine vm = VcCache.getIgnoreMissing(e.getVm().getVm());
         if (vm == null) {
            return false;
         }
         logger.debug("Event received for VM not managed by Serengeti");
         if (rootSerengetiFolder == null) {
            initRootFolder();
         }
         if (rootSerengetiFolder == null) {
            return false;
         }
         if (clusterEntityMgr.getNodeByVmName(vm.getName()) != null
               && VcResourceUtils.insidedRootFolder(rootSerengetiFolder, vm)) {
            logger.info("VM " + vm.getName()
                  + " is Serengeti created VM, add it into meta-db");
            return true;
         }
      }
      return false;
   }

   private void processHostEvent(VcEventType type, Event e) throws Exception {
      logger.info("Received host event " + e);
      HostEvent he = (HostEvent) e;
      String hostName = he.getHost().getName();
      List<NodeEntity> nodes = clusterEntityMgr.getNodesByHost(hostName);
      switch (type) {
      case HostConnected:
      case EnteredMaintenanceMode:
      case ExitMaintenanceMode:
      case HostDisconnected: {
         Thread.sleep(2000);
         VcHost host = VcCache.getIgnoreMissing(he.getHost().getHost());
         host.update();
         for (NodeEntity node : nodes) {
            String moId = node.getMoId();
            if (moId == null) {
               continue;
            }
            VcVirtualMachine vm = VcCache.getIgnoreMissing(moId);
            if (vm == null) {
               continue;
            }
            logger.info("Process VM " + vm.getName()
                  + " for received host event " + type + " of " + hostName);
            if (logger.isDebugEnabled()) {
               logger.debug("host availability: "
                     + !vm.getHost().isUnavailbleForManagement());
               logger.debug("host connection: " + vm.getHost().isConnected());
               logger.debug("host maintenance: "
                     + vm.getHost().isInMaintenanceMode());
               logger.debug("vm connection: " + vm.isConnected());
            }
            String clusterName = CommonUtil.getClusterName(vm.getName());
            try {
               vm.updateRuntime();
               lockMgr.refreshNodeByVmName(clusterName, moId, vm.getName(),
                     true);
               if ((!vm.isConnected())
                     || vm.getHost().isUnavailbleForManagement()) {
                  logConnectionChangeEvent(vm.getName());
               }
            } catch (ManagedObjectNotFound me) {
               continue;
            }
         }
         break;
      }
      case HostRemoved: {
         for (NodeEntity node : nodes) {
            String moId = node.getMoId();
            if (moId == null) {
               continue;
            }
            logger.debug("Remove node " + node.getVmName()
                  + " for host is removed from VC.");
            String clusterName = CommonUtil.getClusterName(node.getVmName());
            lockMgr.removeVmReference(clusterName, moId);
         }
         break;
      }
      }
   }

   private void logConnectionChangeEvent(String vmName) {
      String message =
            "VM "
                  + vmName
                  + " connection state changed. "
                  + "For any operations you did on the cluster in the VM "
                  + "disconnected time, you need to repeat them for this VM manually.";
      logger.warn(message);
   }

   private void processEvent(VcEventType type, Event e, boolean external)
         throws Exception {
      if (e instanceof HostEvent) {
         processHostEvent(type, e);
         return;
      }
      // Event can be either VmEvent or EventEx (TODO: Explicitly check for
      // VM specific EventEx class usage? e.g. VcEventType.VmAppHealthChanged?)
      AuAssert.check(e instanceof VmEvent || e instanceof EventEx);
      ManagedObjectReference moRef = e.getVm().getVm();
      String moId = MoUtil.morefToString(moRef);
      String externalStr = external ? " external" : "";
      logger.debug("processed" + externalStr + " vm event: " + e);
      if (external) {
         if (processExternalEvent(type, e, moId)) {
            VcVirtualMachine vm = VcCache.getIgnoreMissing(e.getVm().getVm());
            String newId = moId;
            if (vm != null) {
               newId = switchMobId(moId, vm);
            }
            processEvent(type, e, newId, true);
         }
      } else {
         processEvent(type, e, moId, false);
      }
   }

   private void processEvent(VcEventType type, Event e, String moId,
         boolean external) throws Exception {
      try {
         switch (type) {
         case VmRemoved: {
            logger.debug("received vm removed event for vm: " + moId);
            NodeEntity node = clusterEntityMgr.getNodeByMobId(moId);
            if (node != null) {
               String clusterName = CommonUtil.getClusterName(node.getVmName());
               lockMgr.refreshNodeByMobId(clusterName, moId, null, true);
            }
            break;
         }
         case VmDisconnected: {
            VcVirtualMachine vm = VcCache.getIgnoreMissing(moId);
            if (vm == null) {
               NodeEntity node = clusterEntityMgr.getNodeByMobId(moId);
               if (node != null) {
                  String clusterName =
                        CommonUtil.getClusterName(node.getVmName());
                  logger.debug("vm " + moId + " is already removed");
                  lockMgr.removeVmReference(clusterName, moId);
               }
               break;
            }
            if (clusterEntityMgr.getNodeByVmName(vm.getName()) != null) {
               vm.updateRuntime();
               if ((!vm.isConnected())
                     || vm.getHost().isUnavailbleForManagement()) {
                  String clusterName = CommonUtil.getClusterName(vm.getName());
                  lockMgr.setNodeConnectionState(clusterName, vm.getName());
                  logConnectionChangeEvent(vm.getName());
               }
            }
            break;
         }
         case VmPoweredOn: {
            logger.debug("vm is powered on");
            // ignore this event if waitForPowerState failed
            if (waitForPowerState(moId, PowerState.poweredOn)) {
               refreshNodeWithAction(moId, true, Constants.NODE_ACTION_WAITING_IP,
                     "Powered On");
               if (external) {
                  NodePowerOnRequest request =
                        new NodePowerOnRequest(lockMgr, moId, clusterManager,
                              softwareManagerCollector);
                  CmsWorker.addRequest(WorkQueue.VC_TASK_NO_DELAY, request);
               }
            }

            break;
         }
         case VmCloned: {
            refreshNodeWithAction(moId, true,
                  Constants.NODE_ACTION_RECONFIGURE, "Cloned");
            break;
         }
         case VmSuspended: {
            refreshNodeWithAction(moId, true, null, "Suspended");
            break;
         }
         case VmPoweredOff: {
            if (waitForPowerState(moId, PowerState.poweredOff)) {
               refreshNodeWithAction(moId, true, null, "Powered Off");
            }
            break;
         }
         case VmConnected: {
            try {
               refreshNodeWithAction(moId, false, null, type.name());
            } catch (AuroraException ex) {
               // vm is not able to be accessed immediately after it's created,
               // ignore the exception here to continue other event processing
               logger.warn("Catch aurora exception " + ex.getMessage()
                     + ", ignore it.");
            }
            break;
         }
         case VmMigrated: {
            refreshNodeWithAction(moId, false, null, type.name());
            break;
         }
         case VhmError:
         case VhmWarning: {
            EventEx event = (EventEx) e;
            VcVirtualMachine vm =
                  VcCache.getIgnoreMissing(event.getVm().getVm());
            if (vm == null) {
               break;
            }
            if (clusterEntityMgr.getNodeByVmName(vm.getName()) != null) {
               logger.info("received vhm event " + event.getEventTypeId()
                     + " for vm " + vm.getName() + ": " + event.getMessage());
               vm.updateRuntime();
               String clusterName = CommonUtil.getClusterName(vm.getName());
               lockMgr.refreshNodeByVmName(clusterName, moId, vm.getName(),
                     event.getMessage(), true);
            }
            break;
         }
         case VhmInfo: {
            EventEx event = (EventEx) e;
            VcVirtualMachine vm =
                  VcCache.getIgnoreMissing(event.getVm().getVm());
            if (vm == null) {
               break;
            }
            if (clusterEntityMgr.getNodeByVmName(vm.getName()) != null) {
               logger.info("received vhm event " + event.getEventTypeId()
                     + " for vm " + vm.getName() + ": " + event.getMessage());
               vm.updateRuntime();
               String clusterName = CommonUtil.getClusterName(vm.getName());
               lockMgr.refreshNodeByVmName(clusterName, moId, vm.getName(), "",
                     true);
            }
            break;
         }
         default: {
            if (external) {
               VcVirtualMachine vm = VcCache.getIgnoreMissing(moId);
               if (vm == null) {
                  break;
               }
               String clusterName = CommonUtil.getClusterName(vm.getName());
               lockMgr.refreshNodeByVmName(clusterName, moId, vm.getName(),
                     true);
            }
            break;
         }
         }
      } catch (ManagedObjectNotFound exp) {
         VcUtil.processNotFoundException(exp, moId, logger);
      }
   }

   private boolean waitForPowerState(final String moid, final PowerState state) {
      // only handle poweredOff or PoweredOn
      AuAssert.check(state == PowerState.poweredOff || state == PowerState.poweredOn);
      final VcVirtualMachine vm = VcCache.getIgnoreMissing(moid);
      if (vm == null) {
         return false;
      }

      int timeout = WAIT_FOR_VM_STATE_TIMEOUT_SECS;
      try {
         while (timeout > 0) {
            // udpate VM's runtime state from VC
            vm.updateRuntime();
            // If runtime state matches the claimed power state, done.
            if (((state == PowerState.poweredOn) && vm.isPoweredOn())
                  || (state == PowerState.poweredOff && vm.isPoweredOff())) {
               logger.info("synced power state " + state + " on vm: " + moid);
               return true;
            }

            logger.debug("syncing power state " + state + " on vm: " + moid);
            timeout -= WAIT_FOR_VM_STATE_SLEEP_INTERVAL_SECS;
            Thread.sleep(WAIT_FOR_VM_STATE_SLEEP_INTERVAL_SECS * 1000);
         }
      } catch (Exception e) {
         logger.error(e.getMessage());
      }
      return false;
   }

   private void refreshNodeWithAction(String moId, boolean setAction,
         String action, String eventName) throws Exception {
      VcVirtualMachine vm = VcCache.getIgnoreMissing(moId);
      if (vm == null) {
         return;
      }
      if (clusterEntityMgr.getNodeByVmName(vm.getName()) != null) {
         logger.info("received vm " + eventName + " event for vm: "
               + vm.getName());
         vm.updateRuntime();
         String clusterName = CommonUtil.getClusterName(vm.getName());
         if (setAction) {
            lockMgr.refreshNodeByVmName(clusterName, moId, vm.getName(),
                  action, true);
         } else {
            lockMgr.refreshNodeByVmName(clusterName, moId, vm.getName(), true);
         }
      }
      return;
   }

   private String switchMobId(String moId, VcVirtualMachine vm)
         throws Exception {
      // check if ft enabled
      if (vm.getConfig() != null && vm.getConfig().getFtInfo() != null) {
         // ft enabled
         vm.update();
         if (vm.getConfig().getFtInfo().getRole() != 1) {
            // not primary VM
            FaultToleranceSecondaryConfigInfo ftInfo =
                  (FaultToleranceSecondaryConfigInfo) vm.getConfig()
                        .getFtInfo();
            moId = MoUtil.morefToString(ftInfo.getPrimaryVM());
            logger.info("Received secondary VM event, switch to primary VM "
                  + moId);
         }
      }
      return moId;
   }
}
TOP

Related Classes of com.vmware.bdd.service.event.VmEventManager$VcEventWrapper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.