/*************************************************************************** * Copyright (c) 2015 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.resmgmt.impl; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import com.vmware.aurora.global.Configuration; import com.vmware.aurora.vc.VcVirtualMachine; import com.vmware.bdd.apitypes.VirtualMachineRead; import com.vmware.bdd.dal.INodeTemplateDAO; import com.vmware.bdd.entity.NodeTemplateEntity; import com.vmware.bdd.exception.ClusteringServiceException; import com.vmware.bdd.service.resmgmt.INodeTemplateService; import com.vmware.bdd.service.utils.VcResourceUtils; import com.vmware.bdd.utils.CommonUtil; import com.vmware.bdd.utils.ConfigInfo; @Component public class NodeTemplateService implements INodeTemplateService { private static long REFRESH_NODE_TEMPLATES_INTERVAL = 30; // in seconds private static final Logger logger = Logger.getLogger(NodeTemplateService.class); private long lastRefreshTimestamp = 0L; @Autowired private INodeTemplateDAO nodeTemplateDAO; private HashMap<String, String> templateMoidMap = new HashMap<String, String>(); public HashMap<String, String> getTemplateMoidMap() { return templateMoidMap; } public void setTemplateMoidMap(HashMap<String, String> templateMoidMap) { this.templateMoidMap = templateMoidMap; } @Override public VcVirtualMachine getNodeTemplateVMByName(String templateName) { String moid = getNodeTemplateIdByName(templateName); return getNodeTemplateVMByMoid(moid); } @Override public VcVirtualMachine getNodeTemplateVMByMoid(String moid) { return VcResourceUtils.findVM(moid); } @Override public String getNodeTemplateIdByName(String templateName) { logger.info("finding node template moid by name " + templateName); refreshNodeTemplates(); if (!CommonUtil.isBlank(templateName)) { // use the specified node template List<NodeTemplateEntity> entities = nodeTemplateDAO.findByName(templateName); if (entities.size() == 1) { return entities.get(0).getMoid(); } else if (entities.size() == 0) { throw ClusteringServiceException.TEMPLATE_VM_NOT_FOUND(templateName); } else { throw ClusteringServiceException.DUPLICATE_NODE_TEMPLATE(templateName); } } else { // use the default node template List<NodeTemplateEntity> entities = nodeTemplateDAO.findAll(); if (entities.size() == 1) { return entities.get(0).getMoid(); } else if (entities.size() == 0) { throw ClusteringServiceException.NO_AVAILABLE_NODE_TEMPLATE(); } else { throw ClusteringServiceException.MORE_THAN_ONE_NODE_TEMPLATE(); } } } @Override public String getNodeTemplateNameByMoid(String moid) { return getNodeTemplateVMByMoid(moid).getName(); } @Override public VirtualMachineRead getNodeTemplateByMoid(String moid) { return toVirtualMachineRead(nodeTemplateDAO.findByMoid(moid)); } @Override public VirtualMachineRead getNodeTemplateByName(String name) { String moid = getNodeTemplateIdByName(name); return getNodeTemplateByMoid(moid); } @Override @Transactional public List<VirtualMachineRead> getAllNodeTemplates() { refreshNodeTemplates(); List<VirtualMachineRead> templates = new ArrayList<VirtualMachineRead>(); List<NodeTemplateEntity> entities = nodeTemplateDAO.findAllOrderByName(); for (NodeTemplateEntity entity : entities) { templates.add(toVirtualMachineRead(entity)); } return templates; } public VirtualMachineRead toVirtualMachineRead(NodeTemplateEntity entity) { VirtualMachineRead vmr = new VirtualMachineRead(); vmr.setName(entity.getName()); vmr.setMoid(entity.getMoid()); vmr.setTag(entity.getTag()); vmr.setLastModified(entity.getLastModified()); return vmr; } /* * Detect the latest node templates from vCenter and save to db. */ @Override @Transactional public synchronized void refreshNodeTemplates() { long curTime = System.currentTimeMillis() / 1000; if (curTime - this.lastRefreshTimestamp < getRefreshNodeTemplateInterval()) { return; } logger.info("Refreshing node templates from vCenter"); List<VcVirtualMachine> vms = VcResourceUtils.findAllNodeTemplates(); HashSet<String> moids = new HashSet<String>(); HashMap<String, String> nameToMoid = new HashMap<String, String>(); for (VcVirtualMachine vm : vms) { String moid = vm.getId(); moids.add(moid); nameToMoid.put(vm.getName(), moid); long timestamp = System.currentTimeMillis(); NodeTemplateEntity entity = nodeTemplateDAO.findByMoid(moid); if (entity == null) { entity = new NodeTemplateEntity(); convertVirtualMachineToEntity(vm, entity, timestamp); nodeTemplateDAO.insert(entity); } else { convertVirtualMachineToEntity(vm, entity, timestamp); nodeTemplateDAO.update(entity); } } // remove the non-exists templates from DB for (NodeTemplateEntity entity : nodeTemplateDAO.findAll()) { if (!moids.contains(entity.getMoid())) { if ( ConfigInfo.isJustRestored() ) { // for restore and upgrade, we need to get the mapping between // old moid to new moid for all the node templates logger.info("The Serengeti Server was just restored, so create the " + "moid mapping between old and new templates, then update the " + "template id in cluster table."); String oldMoid = entity.getMoid(); String newMoid = nameToMoid.get(entity.getName()); if ( null != newMoid ) { templateMoidMap.put(oldMoid, newMoid); } } nodeTemplateDAO.delete(entity); } } logger.info("Refreshing node templates completed"); this.lastRefreshTimestamp = System.currentTimeMillis() / 1000; } public long getRefreshNodeTemplateInterval() { return Configuration.getLong("vc.refresh.node_templates.interval", REFRESH_NODE_TEMPLATES_INTERVAL); } private void convertVirtualMachineToEntity(VcVirtualMachine vm, NodeTemplateEntity entity, long timestamp) { entity.setMoid(vm.getId()); entity.setName(vm.getName()); Date time = getLastModifiedTime(vm); entity.setLastModified(time); if (entity.getLastModified() != null && time.compareTo(entity.getLastModified()) != 0) { logger.info(String.format("Last modified time or powered on time of VM %s is changed on %s", vm.getName(), time.toString())); } } /* * The last time a VM's configuration is modified or the VM is powered on and changes made to the OS inside. */ private Date getLastModifiedTime(VcVirtualMachine vm) { // The changeVersion is a unique identifier for a given version of the configuration. // This is typically implemented as an ever increasing count or a time-stamp. // Each change to the VM configuration in VM Settings or powering on the VM will update this value. // See https://www.vmware.com/support/developer/converter-sdk/conv50_apireference/vim.vm.ConfigInfo.html // Its value is something like "2015-08-26T08:07:31.366195Z". Calendar cal = javax.xml.bind.DatatypeConverter.parseDateTime(vm.getConfig().getChangeVersion()); Date time = cal.getTime(); logger.debug(String.format("Last modified time or powered on time of VM %s is %s", vm.getName(), time.toString())); return time; } }