jp.primecloud.auto.process.lb.PuppetLoadBalancerProcess.java Source code

Java tutorial

Introduction

Here is the source code for jp.primecloud.auto.process.lb.PuppetLoadBalancerProcess.java

Source

/*
 * Copyright 2014 by SCSK Corporation.
 * 
 * This file is part of PrimeCloud Controller(TM).
 * 
 * PrimeCloud Controller(TM) 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.
 * 
 * PrimeCloud Controller(TM) 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 PrimeCloud Controller(TM). If not, see <http://www.gnu.org/licenses/>.
 */
package jp.primecloud.auto.process.lb;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.BooleanUtils;

import jp.primecloud.auto.common.component.FreeMarkerGenerator;
import jp.primecloud.auto.common.component.PasswordEncryptor;
import jp.primecloud.auto.common.constant.PCCConstant;
import jp.primecloud.auto.common.log.LoggingUtils;
import jp.primecloud.auto.common.status.InstanceStatus;
import jp.primecloud.auto.entity.crud.Component;
import jp.primecloud.auto.entity.crud.ComponentConfig;
import jp.primecloud.auto.entity.crud.ComponentType;
import jp.primecloud.auto.entity.crud.Farm;
import jp.primecloud.auto.entity.crud.Instance;
import jp.primecloud.auto.entity.crud.LoadBalancer;
import jp.primecloud.auto.entity.crud.LoadBalancerHealthCheck;
import jp.primecloud.auto.entity.crud.LoadBalancerInstance;
import jp.primecloud.auto.entity.crud.LoadBalancerListener;
import jp.primecloud.auto.entity.crud.PccSystemInfo;
import jp.primecloud.auto.entity.crud.Platform;
import jp.primecloud.auto.entity.crud.PlatformAws;
import jp.primecloud.auto.entity.crud.User;
import jp.primecloud.auto.exception.AutoException;
import jp.primecloud.auto.exception.MultiCauseException;
import jp.primecloud.auto.log.EventLogger;
import jp.primecloud.auto.process.ProcessLogger;
import jp.primecloud.auto.puppet.PuppetClient;
import jp.primecloud.auto.service.ServiceSupport;
import jp.primecloud.auto.util.MessageUtils;

/**
 * <p>
 * TODO: 
 * </p>
 *
 */
public class PuppetLoadBalancerProcess extends ServiceSupport {

    protected File manifestDir;

    protected FreeMarkerGenerator freeMarkerGenerator;

    protected PuppetClient puppetClient;

    protected ExecutorService executorService;

    protected ProcessLogger processLogger;

    protected EventLogger eventLogger;

    public void configure(final Long loadBalancerNo, final Long componentNo, List<Long> instanceNos) {
        final Map<String, Object> rootMap = createRootMap(loadBalancerNo, componentNo, instanceNos);

        // ????????
        if (instanceNos.size() == 1) {
            configureInstance(loadBalancerNo, componentNo, instanceNos.get(0), rootMap);
            return;
        }

        // 
        List<Callable<Void>> callables = new ArrayList<Callable<Void>>();
        final Map<String, Object> loggingContext = LoggingUtils.getContext();
        for (final Long instanceNo : instanceNos) {
            Callable<Void> callable = new Callable<Void>() {
                @Override
                public Void call() throws Exception {
                    LoggingUtils.setContext(loggingContext);
                    try {
                        Map<String, Object> map = new HashMap<String, Object>(rootMap);
                        configureInstance(loadBalancerNo, componentNo, instanceNo, map);
                    } catch (Exception e) {
                        log.error(e.getMessage(), e);
                        throw e;
                    } finally {
                        LoggingUtils.removeContext();
                    }
                    return null;
                }
            };
            callables.add(callable);
        }

        try {
            List<Future<Void>> futures = executorService.invokeAll(callables);

            // ???
            List<Throwable> throwables = new ArrayList<Throwable>();
            for (Future<Void> future : futures) {
                try {
                    future.get();
                } catch (ExecutionException e) {
                    throwables.add(e.getCause());
                } catch (InterruptedException ignore) {
                }
            }

            // ??
            if (throwables.size() > 0) {
                throw new MultiCauseException(throwables.toArray(new Throwable[throwables.size()]));
            }
        } catch (InterruptedException e) {
        }
    }

    protected void configureInstance(Long loadBalancerNo, Long componentNo, Long instanceNo,
            Map<String, Object> rootMap) {
        LoadBalancer loadBalancer = loadBalancerDao.read(loadBalancerNo);
        Component component = componentDao.read(componentNo);
        Instance instance = instanceDao.read(instanceNo);

        // 
        Map<String, Object> instanceMap = createInstanceMap(instanceNo);
        rootMap.putAll(instanceMap);

        // 
        ComponentType componentType = componentTypeDao.read(component.getComponentTypeNo());
        File manifestFile = new File(manifestDir, instance.getFqdn() + "." + component.getComponentName() + ".pp");

        // ?
        restoreManifest(manifestFile);

        // ????
        String digest = getFileDigest(manifestFile, "UTF-8");

        // ??????????
        if (digest == null && BooleanUtils.isNotTrue(loadBalancer.getEnabled())) {
            return;
        }

        // ??
        String templateName = "loadBalancer_" + componentType.getComponentTypeName() + ".ftl";
        generateManifest(templateName, rootMap, manifestFile, "UTF-8");

        // ?????
        if (digest != null) {
            String newDigest = getFileDigest(manifestFile, "UTF-8");
            if (digest.equals(newDigest)) {
                // ?????
                if (log.isDebugEnabled()) {
                    log.debug(MessageUtils.format("Not changed manifest.(file={0})", manifestFile.getName()));
                }
                return;
            }
        }

        // Puppet?
        try {
            runPuppet(instance, component);
        } finally {
            if (BooleanUtils.isTrue(loadBalancer.getEnabled())) {
                // ??
                backupManifest(manifestFile);
            } else {
                // ?
                deleteManifest(manifestFile);
            }
        }
    }

    protected void runPuppet(Instance instance, Component component) {
        ComponentType componentType = componentTypeDao.read(component.getComponentTypeNo());
        String type = "loadBalancer_" + componentType.getComponentTypeName();

        // Puppet??
        try {
            processLogger.writeLogSupport(ProcessLogger.LOG_DEBUG, component, instance, "PuppetManifestApply",
                    new String[] { instance.getFqdn(), type });

            puppetClient.runClient(instance.getFqdn());

        } catch (RuntimeException e) {
            processLogger.writeLogSupport(ProcessLogger.LOG_DEBUG, component, instance, "PuppetManifestApplyFail",
                    new String[] { instance.getFqdn(), type });

            // ??????????
            String code = (e instanceof AutoException) ? AutoException.class.cast(e).getCode() : null;
            if ("EPUPPET-000003".equals(code) || "EPUPPET-000007".equals(code)) {
                log.warn(e.getMessage());

                processLogger.writeLogSupport(ProcessLogger.LOG_DEBUG, component, instance, "PuppetManifestApply",
                        new String[] { instance.getFqdn(), type });

                try {
                    puppetClient.runClient(instance.getFqdn());

                } catch (RuntimeException e2) {
                    processLogger.writeLogSupport(ProcessLogger.LOG_DEBUG, component, instance,
                            "PuppetManifestApplyFail", new String[] { instance.getFqdn(), type });

                    throw e2;
                }
            } else {
                throw e;
            }
        }

        processLogger.writeLogSupport(ProcessLogger.LOG_DEBUG, component, instance, "PuppetManifestApplyFinish",
                new String[] { instance.getFqdn(), type });
    }

    protected Map<String, Object> createRootMap(Long loadBalancerNo, Long componentNo, List<Long> instanceNos) {
        Map<String, Object> map = new HashMap<String, Object>();

        // Component
        Component component = componentDao.read(componentNo);
        map.put("component", component);

        // Instance
        List<Instance> instances = instanceDao.readInInstanceNos(instanceNos);
        map.put("instances", instances);

        // Farm
        Farm farm = farmDao.read(component.getFarmNo());
        map.put("farm", farm);

        // User
        User user = userDao.read(farm.getUserNo());
        PccSystemInfo pccSystemInfo = pccSystemInfoDao.read();
        PasswordEncryptor encryptor = new PasswordEncryptor();
        String decryptPass = encryptor.decrypt(user.getPassword(), pccSystemInfo.getSecretKey());
        user.setPassword(decryptPass);
        map.put("user", user);

        // ComponentConfig
        List<ComponentConfig> componentConfigs = componentConfigDao.readByComponentNo(componentNo);
        Map<String, Object> configs = new HashMap<String, Object>();
        for (ComponentConfig componentConfig : componentConfigs) {
            configs.put(componentConfig.getConfigName(), componentConfig.getConfigValue());
        }
        map.put("configs", configs);

        // ?
        Map<String, Object> loadBalancerMap = createLoadBalancerMap(loadBalancerNo);
        map.putAll(loadBalancerMap);

        return map;
    }

    protected Map<String, Object> createLoadBalancerMap(Long loadBalancerNo) {
        Map<String, Object> map = new HashMap<String, Object>();

        // LoadBalancer
        LoadBalancer loadBalancer = loadBalancerDao.read(loadBalancerNo);
        map.put("loadBalancer", loadBalancer);

        // LoadBalancerListener
        List<LoadBalancerListener> allListeners = loadBalancerListenerDao.readByLoadBalancerNo(loadBalancerNo);
        List<LoadBalancerListener> listeners = new ArrayList<LoadBalancerListener>();
        for (LoadBalancerListener listener : allListeners) {
            if (BooleanUtils.isTrue(listener.getEnabled())) {
                listeners.add(listener);
            }
        }
        map.put("listeners", listeners);

        // LoadBalancerHealthCheck
        LoadBalancerHealthCheck healthCheck = loadBalancerHealthCheckDao.read(loadBalancerNo);
        map.put("healthCheck", healthCheck);

        // LoadBalancerinstance
        List<LoadBalancerInstance> lbInstances = loadBalancerInstanceDao.readByLoadBalancerNo(loadBalancerNo);
        List<Long> targetInstanceNos = new ArrayList<Long>();
        for (LoadBalancerInstance lbInstance : lbInstances) {
            if (BooleanUtils.isTrue(lbInstance.getEnabled())) {
                targetInstanceNos.add(lbInstance.getInstanceNo());
            }
        }
        List<Instance> tmpInstances = instanceDao.readInInstanceNos(targetInstanceNos);
        List<Instance> targetInstances = new ArrayList<Instance>();
        for (Instance tmpInstance : tmpInstances) {
            if (BooleanUtils.isTrue(tmpInstance.getEnabled())) {
                InstanceStatus status = InstanceStatus.fromStatus(tmpInstance.getStatus());
                if (status == InstanceStatus.RUNNING) {
                    targetInstances.add(tmpInstance);
                }
            }
        }
        map.put("targetInstances", targetInstances);

        return map;
    }

    protected Map<String, Object> createInstanceMap(Long instanceNo) {
        Map<String, Object> map = new HashMap<String, Object>();

        // Instance
        Instance instance = instanceDao.read(instanceNo);
        map.put("instance", instance);

        // IP
        List<Instance> allInstances = instanceDao.readByFarmNo(instance.getFarmNo());
        Platform platform = platformDao.read(instance.getPlatformNo());
        Map<String, String> accessIps = new HashMap<String, String>();
        for (Instance instance2 : allInstances) {
            // ??????
            InstanceStatus status = InstanceStatus.fromStatus(instance2.getStatus());
            if (status != InstanceStatus.RUNNING) {
                continue;
            }

            // ?publicIp??
            String accessIp = instance2.getPublicIp();
            if (instance.getPlatformNo().equals(instance2.getPlatformNo())) {
                // ????
                // TODO CLOUD BRANCHING
                if (PCCConstant.PLATFORM_TYPE_AWS.equals(platform.getPlatformType())) {
                    PlatformAws platformAws = platformAwsDao.read(instance2.getPlatformNo());
                    if (BooleanUtils.isFalse(platformAws.getVpc())) {
                        // VPC?????privateIp??
                        accessIp = instance2.getPrivateIp();
                    }
                } else if (PCCConstant.PLATFORM_TYPE_CLOUDSTACK.equals(platform.getPlatformType())) {
                    // CloudStack???getPublicIp??
                    accessIp = instance2.getPublicIp();
                } else if (PCCConstant.PLATFORM_TYPE_VMWARE.equals(platform.getPlatformType())) {
                    // VMware???privateIp??
                    accessIp = instance2.getPrivateIp();
                    //nifty
                } else if (PCCConstant.PLATFORM_TYPE_NIFTY.equals(platform.getPlatformType())) {
                    // ???privateIp??
                    accessIp = instance2.getPrivateIp();
                } else if (PCCConstant.PLATFORM_TYPE_VCLOUD.equals(platform.getPlatformType())) {
                    // VCloud???privateIp??
                    accessIp = instance2.getPrivateIp();
                } else if (PCCConstant.PLATFORM_TYPE_AZURE.equals(platform.getPlatformType())) {
                    // Azure???getPublicIp??
                    accessIp = instance2.getPublicIp();
                } else if (PCCConstant.PLATFORM_TYPE_OPENSTACK.equals(platform.getPlatformType())) {
                    // Openstack???getPublicIp??
                    accessIp = instance2.getPublicIp();
                }
            }
            accessIps.put(instance2.getInstanceNo().toString(), accessIp);
        }
        map.put("accessIps", accessIps);

        // ???IP
        List<String> listenIps = new ArrayList<String>();
        // TODO CLOUD BRANCHING
        if (PCCConstant.PLATFORM_TYPE_AWS.equals(platform.getPlatformType())) {
            // AWS??
            listenIps.add(instance.getPrivateIp());
            PlatformAws platformAws = platformAwsDao.read(instance.getPlatformNo());
            if (BooleanUtils.isFalse(platform.getInternal()) && BooleanUtils.isFalse(platformAws.getVpc())) {
                // ?AWS?VPN??(VPC+VPN?????VPN??)?PublicIp????
                listenIps.add(instance.getPublicIp());
            }
        } else if (PCCConstant.PLATFORM_TYPE_CLOUDSTACK.equals(platform.getPlatformType())) {
            // CloudStack??
            listenIps.add(instance.getPublicIp());
            listenIps.add(instance.getPrivateIp());
        } else if (PCCConstant.PLATFORM_TYPE_VMWARE.equals(platform.getPlatformType())) {
            // VMware??
            listenIps.add(instance.getPublicIp());
            listenIps.add(instance.getPrivateIp());
        } else if (PCCConstant.PLATFORM_TYPE_NIFTY.equals(platform.getPlatformType())) {
            // Nifty??
            listenIps.add(instance.getPublicIp());
            listenIps.add(instance.getPrivateIp());
        } else if (PCCConstant.PLATFORM_TYPE_VCLOUD.equals(platform.getPlatformType())) {
            // VCloud??
            listenIps.add(instance.getPublicIp());
            listenIps.add(instance.getPrivateIp());
        } else if (PCCConstant.PLATFORM_TYPE_AZURE.equals(platform.getPlatformType())) {
            // Azure??
            listenIps.add(instance.getPublicIp());
            listenIps.add(instance.getPrivateIp());
        } else if (PCCConstant.PLATFORM_TYPE_OPENSTACK.equals(platform.getPlatformType())) {
            // Openstack??
            listenIps.add(instance.getPublicIp());
            listenIps.add(instance.getPrivateIp());
        }

        map.put("listenIps", listenIps);

        return map;
    }

    protected void generateManifest(String templateName, Map<String, Object> rootMap, File file, String encoding) {
        String data = freeMarkerGenerator.generate(templateName, rootMap);

        // ??Puppet?LF????????????
        data = data.replaceAll("\r\n", "\n");

        // ??
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }

        // 
        try {
            FileUtils.writeStringToFile(file, data, encoding);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    protected String getFileDigest(File file, String encoding) {
        if (!file.exists()) {
            return null;
        }
        try {
            String content = FileUtils.readFileToString(file, encoding);
            return DigestUtils.shaHex(content);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    protected void restoreManifest(File manifestFile) {
        // ?
        File backupDir = new File(manifestDir, "backup");
        File backupFile = new File(backupDir, manifestFile.getName());

        if (!backupFile.exists()) {
            return;
        }

        try {
            if (manifestFile.exists()) {
                FileUtils.forceDelete(manifestFile);
            }
            FileUtils.moveFile(backupFile, manifestFile);
        } catch (IOException e) {
            // ?
            log.warn(e.getMessage());
        }
    }

    protected void backupManifest(File manifestFile) {
        if (!manifestFile.exists()) {
            return;
        }

        // ??
        File backupDir = new File(manifestDir, "backup");
        File backupFile = new File(backupDir, manifestFile.getName());
        try {
            if (!backupDir.exists()) {
                backupDir.mkdir();
            }
            if (backupFile.exists()) {
                FileUtils.forceDelete(backupFile);
            }
            FileUtils.moveFile(manifestFile, backupFile);
        } catch (IOException e) {
            // ??
            log.warn(e.getMessage());
        }
    }

    protected void deleteManifest(File manifestFile) {
        // ?
        if (!manifestFile.exists()) {
            return;
        }
        try {
            FileUtils.forceDelete(manifestFile);
        } catch (IOException e) {
            // ?
            log.warn(e.getMessage());
        }
    }

    /**
     * manifestDir???
     *
     * @param manifestDir manifestDir
     */
    public void setManifestDir(File manifestDir) {
        this.manifestDir = manifestDir;
    }

    /**
     * freeMarkerGenerator???
     *
     * @param freeMarkerGenerator freeMarkerGenerator
     */
    public void setFreeMarkerGenerator(FreeMarkerGenerator freeMarkerGenerator) {
        this.freeMarkerGenerator = freeMarkerGenerator;
    }

    /**
     * puppetClient???
     *
     * @param puppetClient puppetClient
     */
    public void setPuppetClient(PuppetClient puppetClient) {
        this.puppetClient = puppetClient;
    }

    /**
     * executorService???
     *
     * @param executorService executorService
     */
    public void setExecutorService(ExecutorService executorService) {
        this.executorService = executorService;
    }

    /**
     * eventLogger???
     *
     * @param eventLogger eventLogger
     */
    public void setEventLogger(EventLogger eventLogger) {
        this.eventLogger = eventLogger;
    }

    /**
     * processLogger???
     *
     * @param processLogger processLogger
     */
    public void setProcessLogger(ProcessLogger processLogger) {
        this.processLogger = processLogger;
    }

}