jp.primecloud.auto.process.puppet.PuppetNodeProcess.java Source code

Java tutorial

Introduction

Here is the source code for jp.primecloud.auto.process.puppet.PuppetNodeProcess.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.puppet;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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

import jp.primecloud.auto.common.component.FreeMarkerGenerator;
import jp.primecloud.auto.common.component.PasswordEncryptor;
import jp.primecloud.auto.common.component.PasswordGenerator;
import jp.primecloud.auto.common.constant.PCCConstant;
import jp.primecloud.auto.config.Config;
import jp.primecloud.auto.entity.crud.AwsVolume;
import jp.primecloud.auto.entity.crud.AzureDisk;
import jp.primecloud.auto.entity.crud.CloudstackVolume;
import jp.primecloud.auto.entity.crud.Component;
import jp.primecloud.auto.entity.crud.ComponentInstance;
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.OpenstackVolume;
import jp.primecloud.auto.entity.crud.PccSystemInfo;
import jp.primecloud.auto.entity.crud.Platform;
import jp.primecloud.auto.entity.crud.PuppetInstance;
import jp.primecloud.auto.entity.crud.User;
import jp.primecloud.auto.entity.crud.VcloudDisk;
import jp.primecloud.auto.entity.crud.VmwareDisk;
import jp.primecloud.auto.exception.AutoException;
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 PuppetNodeProcess extends ServiceSupport {

    protected File manifestDir;

    protected FreeMarkerGenerator freeMarkerGenerator;

    protected PuppetClient puppetClient;

    protected PasswordGenerator passwordGenerator = new PasswordGenerator();

    protected ProcessLogger processLogger;

    protected EventLogger eventLogger;

    public void startNode(Long instanceNo) {
        PuppetInstance puppetInstance = puppetInstanceDao.read(instanceNo);
        if (puppetInstance == null) {
            // Puppet????
            throw new AutoException("EPROCESS-000301", instanceNo);
        }

        Instance instance = instanceDao.read(instanceNo);

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100201", instanceNo, instance.getInstanceName()));
        }

        // 
        processLogger.writeLogSupport(ProcessLogger.LOG_DEBUG, null, instance, "InstanceBaseStart", null);

        // PuppetMaster?
        createPassword(instanceNo);

        // Puppet??
        checkClient(instanceNo);

        // ??
        Map<String, Object> rootMap = createNodeMap(instanceNo, true);

        // ??
        createNodeManifest(instanceNo, true, rootMap);

        // ?
        restoreManifest(instanceNo);

        try {
            // ??
            configureInstance(instanceNo, true, rootMap);
        } finally {
            // ??
            backupManifest(instanceNo);
        }

        // 
        processLogger.writeLogSupport(ProcessLogger.LOG_DEBUG, null, instance, "InstanceBaseStartFinish", null);

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100202", instanceNo, instance.getInstanceName()));
        }
    }

    public void stopNode(Long instanceNo) {
        PuppetInstance puppetInstance = puppetInstanceDao.read(instanceNo);
        if (puppetInstance == null) {
            // Puppet????
            throw new AutoException("EPROCESS-000301", instanceNo);
        }

        Instance instance = instanceDao.read(instanceNo);

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100203", instanceNo, instance.getInstanceName()));
        }

        // 
        processLogger.writeLogSupport(ProcessLogger.LOG_DEBUG, null, instance, "InstanceBaseStop", null);

        // ??
        Map<String, Object> rootMap = createNodeMap(instanceNo, false);

        // ?
        restoreManifest(instanceNo);

        try {
            // ??
            configureInstance(instanceNo, false, rootMap);
        } finally {
            // ?
            deleteManifest(instanceNo);
        }

        // PuppetMaster?
        deletePassword(instanceNo);

        // Puppet??
        clearCa(instanceNo);

        // 
        processLogger.writeLogSupport(ProcessLogger.LOG_DEBUG, null, instance, "InstanceBaseStopFinish", null);

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100204", instanceNo, instance.getInstanceName()));
        }
    }

    protected void createNodeManifest(Long instanceNo, boolean start, Map<String, Object> rootMap) {
        Instance instance = instanceDao.read(instanceNo);

        // ??
        File manifestFile = new File(manifestDir, instance.getFqdn() + ".pp");
        generateManifest("node.ftl", rootMap, manifestFile, "UTF-8");
    }

    protected void configureInstance(Long instanceNo, boolean start, Map<String, Object> rootMap) {
        Instance instance = instanceDao.read(instanceNo);

        File manifestFile = new File(manifestDir, instance.getFqdn() + ".base.pp");

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

        // ?????????
        if (digest == null && !start) {
            return;
        }

        // ??
        generateManifest("base.ftl", 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);
        } catch (RuntimeException e) {
            if (!start) {
                // puppetrun??????
                log.warn(e.getMessage());
            } else {
                throw e;
            }
        }
    }

    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 void runPuppet(Instance instance) {
        // Puppet??
        try {
            processLogger.writeLogSupport(ProcessLogger.LOG_DEBUG, null, instance, "PuppetManifestApply",
                    new String[] { instance.getFqdn(), "base" });

            puppetClient.runClient(instance.getFqdn());

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

            // ??????????
            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, null, instance, "PuppetManifestApply",
                        new String[] { instance.getFqdn(), "base" });

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

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

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

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

    protected Map<String, Object> createNodeMap(Long instanceNo, boolean start) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("start", start);

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

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

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

        // Component
        List<Component> components = componentDao.readByFarmNo(instance.getFarmNo());
        map.put("components", components);
        Map<Long, Component> componentMap = new HashMap<Long, Component>();
        for (Component component : components) {
            componentMap.put(component.getComponentNo(), component);
        }

        // ComponentType
        List<ComponentType> componentTypes = componentTypeDao.readAll();
        Map<Long, ComponentType> componentTypeMap = new HashMap<Long, ComponentType>();
        for (ComponentType componentType : componentTypes) {
            componentTypeMap.put(componentType.getComponentTypeNo(), componentType);
        }

        // PuppetInstance
        PuppetInstance puppetInstance = puppetInstanceDao.read(instanceNo);
        map.put("puppetInstance", puppetInstance);

        // Platform
        Platform platform = platformDao.read(instance.getPlatformNo());
        map.put("platform", platform);
        // TODO CLOUD BRANCHING
        if (PCCConstant.PLATFORM_TYPE_AWS.equals(platform.getPlatformType())) {
            // AwsVolume
            List<AwsVolume> awsVolumes = awsVolumeDao.readByInstanceNo(instanceNo);
            map.put("awsVolumes", awsVolumes);
        } else if (PCCConstant.PLATFORM_TYPE_CLOUDSTACK.equals(platform.getPlatformType())) {
            // CloudStackVolume
            List<CloudstackVolume> cloudstackVolumes = cloudstackVolumeDao.readByInstanceNo(instanceNo);
            map.put("cloudstackVolumes", cloudstackVolumes);
        } else if (PCCConstant.PLATFORM_TYPE_VMWARE.equals(platform.getPlatformType())) {
            // VmwareDisk
            List<VmwareDisk> vmwareDisks = vmwareDiskDao.readByInstanceNo(instanceNo);
            map.put("vmwareDisks", vmwareDisks);
        } else if (PCCConstant.PLATFORM_TYPE_VCLOUD.equals(platform.getPlatformType())) {
            // VcloudDisk
            List<VcloudDisk> vcloudDisks = vcloudDiskDao.readByInstanceNo(instanceNo);
            map.put("vcloudDisks", vcloudDisks);
        } else if (PCCConstant.PLATFORM_TYPE_AZURE.equals(platform.getPlatformType())) {
            // AzureDisk
            List<AzureDisk> azureDisks = azureDiskDao.readByInstanceNo(instanceNo);
            map.put("azureDisks", azureDisks);
        } else if (PCCConstant.PLATFORM_TYPE_OPENSTACK.equals(platform.getPlatformType())) {
            // OpenstackVolume
            List<OpenstackVolume> osVolumes = openstackVolumeDao.readByInstanceNo(instanceNo);
            map.put("osVolumes", osVolumes);
        }

        // ???
        map.put("zabbixServer", Config.getProperty("zabbix.server"));
        map.put("rsyslogServer", Config.getProperty("rsyslog.server"));

        // Zabbix???IP
        String zabbixListenIp = instance.getPublicIp();
        if (PCCConstant.PLATFORM_TYPE_AWS.equals(platform.getPlatformType())) {
            if (BooleanUtils.isTrue(platform.getInternal())) {
                // ?AWS???privateIp????
                // ????????
                // Eucalyptus
                // AWS
                // ?VPC(VPC+VPN???)
                zabbixListenIp = instance.getPrivateIp();
            }
        }
        map.put("zabbixListenIp", zabbixListenIp);

        // Zabbix ??
        // Zabbix?????? prefix + - + fqdn ??
        // prefix?config.properties??
        String zabbixHostname = instance.getFqdn();
        if (StringUtils.isNotEmpty(Config.getProperty("zabbix.prefix"))) {
            zabbixHostname = Config.getProperty("zabbix.prefix") + "-" + instance.getFqdn();
        }
        log.debug("zabbixHostname =" + zabbixHostname);
        map.put("zabbixHostname", zabbixHostname);

        // ???
        List<Component> associatedComponents = new ArrayList<Component>();
        List<ComponentType> associatedComponentTypes = new ArrayList<ComponentType>();
        List<ComponentInstance> componentInstances = componentInstanceDao.readByInstanceNo(instanceNo);
        for (ComponentInstance componentInstance : componentInstances) {
            // ??
            if (BooleanUtils.isNotTrue(componentInstance.getEnabled())
                    || BooleanUtils.isNotTrue(componentInstance.getAssociate())) {
                continue;
            }

            for (Component component : components) {
                if (component.getComponentNo().equals(componentInstance.getComponentNo())) {
                    associatedComponents.add(component);
                    ComponentType componentType = componentTypeDao.read(component.getComponentTypeNo());
                    associatedComponentTypes.add(componentType);
                }
            }
        }

        map.put("associatedComponents", associatedComponents);
        map.put("associatedComponentTypes", associatedComponentTypes);

        //????(???,????)
        Map<String, String> componentTypeNameMap = new HashMap<String, String>();
        for (ComponentInstance componentInstance : componentInstances) {
            if (!componentTypeNameMap.containsKey(componentInstance.getComponentNo())) {
                Component component = componentMap.get(componentInstance.getComponentNo());
                ComponentType componentType = componentTypeMap.get(component.getComponentTypeNo());
                componentTypeNameMap.put(componentInstance.getComponentNo().toString(),
                        componentType.getComponentTypeName());
            }
        }

        map.put("componentTypeNameMap", componentTypeNameMap);
        return map;
    }

    protected void restoreManifest(Long instanceNo) {
        Instance instance = instanceDao.read(instanceNo);
        File manifestFile = new File(manifestDir, instance.getFqdn() + ".base.pp");

        // ?
        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(Long instanceNo) {
        Instance instance = instanceDao.read(instanceNo);
        File manifestFile = new File(manifestDir, instance.getFqdn() + ".base.pp");

        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(Long instanceNo) {
        Instance instance = instanceDao.read(instanceNo);

        // ??
        final String fqdn = instance.getFqdn();
        File[] manifestFiles = manifestDir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.startsWith(fqdn) && name.endsWith(".pp");
            }
        });

        // ?
        for (File manifestFile : manifestFiles) {
            try {
                if (manifestFile.exists()) {
                    FileUtils.forceDelete(manifestFile);
                }
            } catch (IOException e) {
                // ?
                log.warn(e.getMessage());
            }
        }
    }

    protected void createPassword(Long instanceNo) {
        PuppetInstance puppetInstance = puppetInstanceDao.read(instanceNo);

        // ??????
        if (StringUtils.isNotEmpty(puppetInstance.getPassword())) {
            return;
        }

        // 
        String password = passwordGenerator.generate(50);

        // 
        puppetInstance.setPassword(password);
        puppetInstanceDao.update(puppetInstance);
    }

    protected void deletePassword(Long instanceNo) {
        PuppetInstance puppetInstance = puppetInstanceDao.read(instanceNo);

        // ?????
        if (StringUtils.isEmpty(puppetInstance.getPassword())) {
            return;
        }

        puppetInstance.setPassword(null);
        puppetInstanceDao.update(puppetInstance);
    }

    protected void checkClient(Long instanceNo) {
        Instance instance = instanceDao.read(instanceNo);

        // Puppet????????
        int retry = 20;
        for (int count = 0; count <= retry; count++) {
            List<String> clients = puppetClient.listClients();
            if (clients.contains(instance.getFqdn())) {
                break;
            }

            if (count == retry) {
                throw new AutoException("EPROCESS-000302", instance.getFqdn());
            }

            try {
                Thread.sleep(1000 * 15);
            } catch (InterruptedException ignore) {
            }
        }
    }

    protected void clearCa(Long instanceNo) {
        Instance instance = instanceDao.read(instanceNo);
        puppetClient.clearCa(instance.getFqdn());
    }

    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);
        }
    }

    /**
     * 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;
    }

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

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

}