com.vmware.bdd.aop.software.DefaultPreStartServicesAdvice.java Source code

Java tutorial

Introduction

Here is the source code for com.vmware.bdd.aop.software.DefaultPreStartServicesAdvice.java

Source

/***************************************************************************
 * Copyright (c) 2012-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.aop.software;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;

import com.vmware.bdd.software.mgmt.exception.SoftwareManagementException;
import com.vmware.bdd.software.mgmt.plugin.exception.SoftwareManagementPluginException;
import com.vmware.bdd.software.mgmt.plugin.intf.PreStartServices;
import com.vmware.bdd.utils.JobUtils;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.transaction.annotation.Transactional;

import com.vmware.aurora.composition.concurrent.ExecutionResult;
import com.vmware.aurora.composition.concurrent.Priority;
import com.vmware.aurora.composition.concurrent.Scheduler;
import com.vmware.aurora.vc.VcCache;
import com.vmware.aurora.vc.VcVirtualMachine;
import com.vmware.aurora.vc.vcservice.VcContext;
import com.vmware.aurora.vc.vcservice.VcSession;
import com.vmware.bdd.entity.ClusterEntity;
import com.vmware.bdd.entity.NodeEntity;
import com.vmware.bdd.exception.BddException;
import com.vmware.bdd.manager.intf.IClusterEntityManager;
import com.vmware.bdd.service.sp.NoProgressUpdateCallback;
import com.vmware.bdd.software.mgmt.plugin.aop.PreConfiguration;
import com.vmware.bdd.software.mgmt.plugin.exception.InfrastructureException;
import com.vmware.bdd.utils.VcVmUtil;

@Aspect
public class DefaultPreStartServicesAdvice implements PreStartServices {
    private static final Logger logger = Logger.getLogger(DefaultPreStartServicesAdvice.class);
    private IClusterEntityManager clusterEntityMgr;

    public IClusterEntityManager getClusterEntityMgr() {
        return clusterEntityMgr;
    }

    @Autowired
    public void setClusterEntityMgr(IClusterEntityManager clusterEntityMgr) {
        this.clusterEntityMgr = clusterEntityMgr;
    }

    @Around("@annotation(com.vmware.bdd.software.mgmt.plugin.aop.PreConfiguration)")
    public Object preClusterConfiguration(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        PreConfiguration beforeConfig = AnnotationUtils.findAnnotation(method, PreConfiguration.class);
        String nameParam = beforeConfig.clusterNameParam();

        String[] paramNames = signature.getParameterNames();
        Object[] args = pjp.getArgs();
        String clusterName = null;
        for (int i = 0; i < paramNames.length; i++) {
            if (paramNames[i].equals(nameParam)) {
                clusterName = (String) args[i];
            }
        }
        if (clusterName == null) {
            logger.error("Cluster name is not specified in method");
            throw BddException.INTERNAL(null, "Wrong annotation usage. Cluster name must be specified in method.");
        }
        ClusterEntity cluster = clusterEntityMgr.findByName(clusterName);
        if (cluster == null) {
            throw BddException.NOT_FOUND("Cluster", clusterName);
        }
        preStartServices(clusterName);
        return pjp.proceed();
    }

    @Override
    public void preStartServices(String clusterName) throws SoftwareManagementPluginException {
        preStartServices(clusterName, false);
    }

    @Override
    public void preStartServices(String clusterName, boolean forceStart) throws SoftwareManagementPluginException {
        logger.info("Pre configuration for cluster " + clusterName);
        synchronized (this) {
            if (clusterEntityMgr == null) {
                ApplicationContext context = new ClassPathXmlApplicationContext(
                        "classpath*:/../spring/*-context.xml");
                clusterEntityMgr = (IClusterEntityManager) context.getBean("clusterEntityManager");
            }
        }

        waitVmBootup(clusterName, forceStart);

        updateNodes(clusterName, forceStart);
    }

    private void waitVmBootup(String clusterName, boolean forceStart) {
        List<NodeEntity> nodes = clusterEntityMgr.findAllNodes(clusterName);
        Callable<Void>[] callables = new Callable[nodes.size()];
        int i = 0;
        for (NodeEntity node : nodes) {
            WaitVMStatusTask task = new WaitVMStatusTask(node.getMoId());
            callables[i] = task;
            i++;
        }
        try {
            NoProgressUpdateCallback callback = new NoProgressUpdateCallback();
            ExecutionResult[] result = Scheduler.executeStoredProcedures(Priority.INTERACTIVE, callables, callback);
            if (result.length == 0) {
                logger.error("Waiting for nodes bootup task is not executed.");
                throw BddException.INTERNAL(null, "Waiting for nodes bootup task is not executed.");
            }
            List<String> errorMsgList = new ArrayList<String>();
            for (i = 0; i < callables.length; i++) {
                if (result[i].throwable != null) {
                    errorMsgList.add(result[i].throwable.getMessage());
                }
            }
            if (!errorMsgList.isEmpty()) {
                logger.error(errorMsgList);
                JobUtils.forceClusterOperationRecordError(forceStart, logger);
                if (!forceStart) {
                    throw InfrastructureException.WAIT_VM_STATUS_FAIL(clusterName, errorMsgList);
                }
            }
        } catch (InterruptedException e) {
            String errorMessage = "error when waiting for nodes bootup";
            logger.error(errorMessage, e);
            JobUtils.forceClusterOperationRecordError(forceStart, logger);
            if (!forceStart) {
                throw BddException.INTERNAL(e, e.getMessage());
            }
        }
    }

    @Transactional
    private Void updateNodes(final String clusterName, final boolean forceStart) {

        return VcContext.inVcSessionDo(new VcSession<Void>() {
            @Override
            protected Void body() throws Exception {

                List<NodeEntity> nodes = clusterEntityMgr.findAllNodes(clusterName);
                for (NodeEntity node : nodes) {
                    if (node.getMoId() == null || node.getMoId().isEmpty()) {
                        continue;
                    }
                    node = clusterEntityMgr.getNodeWithNicsByMobId(node.getMoId());
                    VcVirtualMachine vm = VcCache.getIgnoreMissing(node.getMoId());
                    String hostname = VcVmUtil.getMgtHostName(vm, node.getPrimaryMgtIpV4());
                    if (hostname == null || hostname.isEmpty()) {
                        logger.error("Failed to get FQDN from vm " + vm.getName());
                        JobUtils.forceClusterOperationRecordError(forceStart, logger);
                        if (!forceStart) {
                            throw SoftwareManagementException.FAILED_TO_GET_FQDN(vm.getName());
                        }
                    }
                    if (!hostname.equals(node.getGuestHostName())) {
                        node.setGuestHostName(hostname);
                        clusterEntityMgr.update(node);
                        logger.info("Update management NIC FQDN of node " + node.getVmName() + " to "
                                + node.getGuestHostName());
                    }
                }

                return null;
            }
        });

    }
}