com.athena.peacock.controller.web.machine.MachineService.java Source code

Java tutorial

Introduction

Here is the source code for com.athena.peacock.controller.web.machine.MachineService.java

Source

/* 
 * Athena Peacock Project - Server Provisioning Engine for IDC or Cloud
 * 
 * Copyright (C) 2013 Open Source Consulting, Inc. All rights reserved by Open Source Consulting, Inc.
 *
 * This program 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.
 * 
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 * Revision History
 * Author         Date            Description
 * ---------------   ----------------   ------------
 * Sang-cheon Park   2013. 8. 25.      First Draft.
 */
package com.athena.peacock.controller.web.machine;

import java.io.IOException;
import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestClientException;

import com.athena.peacock.common.core.action.FileWriteAction;
import com.athena.peacock.common.core.action.ShellAction;
import com.athena.peacock.common.core.action.support.TargetHost;
import com.athena.peacock.common.core.command.Command;
import com.athena.peacock.common.core.util.SshExecUtil;
import com.athena.peacock.common.netty.PeacockDatagram;
import com.athena.peacock.common.netty.message.AbstractMessage;
import com.athena.peacock.common.netty.message.ProvisioningCommandMessage;
import com.athena.peacock.controller.common.component.RHEVMRestTemplateManager;
import com.athena.peacock.controller.netty.PeacockTransmitter;
import com.athena.peacock.controller.web.rhevm.RHEVApi;
import com.redhat.rhevm.api.model.VM;

/**
 * <pre>
 * 
 * </pre>
 * @author Sang-cheon Park
 * @version 1.0
 */
@Service("machineService")
@Transactional(rollbackFor = { Throwable.class }, propagation = Propagation.REQUIRED)
public class MachineService {

    protected final Logger logger = LoggerFactory.getLogger(MachineService.class);

    @Inject
    @Named("machineDao")
    private MachineDao machineDao;

    @Inject
    @Named("peacockTransmitter")
    private PeacockTransmitter peacockTransmitter;

    public void insertMachine(MachineDto machine) throws Exception {
        MachineDto m = machineDao.getMachine(machine.getMachineId());

        if (m != null) {
            if (StringUtils.isEmpty(machine.getDisplayId())) {
                machine.setDisplayId(m.getDisplayId());
            }
            if (StringUtils.isEmpty(machine.getDisplayName())) {
                machine.setDisplayName(m.getDisplayName());
                machine.setIsPrd(m.getIsPrd());
            }
            // Edit Instance ?  IP  RHEV Manager ? ??  
            // hypervisorId ? cluster    .
            // ?  ?  .
            if (StringUtils.isEmpty(machine.getCluster())) {
                machine.setCluster(m.getCluster());
                machine.setIsVm(m.getIsVm());
            }
            if (machine.getHypervisorId() == null) {
                machine.setHypervisorId(m.getHypervisorId());
                machine.setIsVm(m.getIsVm());
            }
            machineDao.updateMachine(machine);
        } else {
            String displayId = "i-" + RandomStringUtils.randomAlphanumeric(8).toLowerCase();

            while (true) {
                if (machineDao.checkDuplicateDisplayId(displayId) == 0) {
                    machine.setDisplayId(displayId);
                    break;
                } else {
                    displayId = "i-" + RandomStringUtils.randomAlphanumeric(8).toLowerCase();
                }
            }

            machineDao.insertMachine(machine);
        }
    }

    public int getMachineListCnt(MachineDto machine) throws Exception {
        return machineDao.getMachineListCnt(machine);
    }

    public List<MachineDto> getMachineList(MachineDto machine) throws Exception {
        return machineDao.getMachineList(machine);
    }

    public MachineDto getMachine(String machineId) throws Exception {
        return machineDao.getMachine(machineId);
    }

    public void deleteMachine(String machineId) throws Exception {
        machineDao.deleteMachine(machineId);
    }

    public void updateMachineOnly(MachineDto machine) throws Exception {
        machineDao.updateMachine(machine);
    }

    public boolean updateMachine(MachineDto machine) throws RestClientException, Exception {
        MachineDto m = machineDao.getMachine(machine.getMachineId());

        boolean hostnameChanged = false;

        logger.debug("[UPDATE_MACHINE] 0. start updateMachine()");

        // Instance ?? ??  DB, RHEV-M ??
        if (!machine.getDisplayName().equals(m.getDisplayName())) {
            if (m.getHypervisorId() != null && m.getHypervisorId() > 0) {
                int major = RHEVMRestTemplateManager.getRHEVMRestTemplate(m.getHypervisorId()).getMajor();
                int minor = RHEVMRestTemplateManager.getRHEVMRestTemplate(m.getHypervisorId()).getMinor();

                VM vm = null;

                double version = Double.parseDouble(major + "." + minor);
                if (version >= 3.2) {
                    vm = new VM();
                    vm.setName(machine.getDisplayName());
                    RHEVMRestTemplateManager.getRHEVMRestTemplate(m.getHypervisorId())
                            .submit(RHEVApi.VMS + "/" + m.getMachineId(), HttpMethod.PUT, vm, "vm", VM.class);
                } else {
                    String callUrl = RHEVApi.VMS + "/" + machine.getMachineId();
                    vm = RHEVMRestTemplateManager.getRHEVMRestTemplate(m.getHypervisorId()).submit(callUrl,
                            HttpMethod.GET, VM.class);

                    if (vm.getStatus().getState().toLowerCase().equals("down")) {
                        vm = new VM();
                        vm.setName(machine.getDisplayName());
                        RHEVMRestTemplateManager.getRHEVMRestTemplate(m.getHypervisorId())
                                .submit(RHEVApi.VMS + "/" + m.getMachineId(), HttpMethod.PUT, vm, "vm", VM.class);
                    } else {
                        throw new Exception("VM_UP_STAT");
                    }
                }
            }

            if (machine.getDisplayName().toLowerCase().startsWith("hhilws")
                    && !machine.getDisplayName().toLowerCase().startsWith("hhilwsd")) {
                m.setIsPrd("Y");
            } else {
                m.setIsPrd("N");
            }

            m.setDisplayName(machine.getDisplayName());
            m.setUpdUserId(machine.getUpdUserId());

            machineDao.updateMachine(m);
        }

        logger.debug("[UPDATE_MACHINE] 1. update machine info.");

        MachineDto add = getAdditionalInfo(machine.getMachineId());
        if (add == null) {
            insertAdditionalInfo(machine);
        } else {
            machine.setApplyYn(add.getApplyYn());

            if (StringUtils.isNotEmpty(machine.getIpAddress())
                    && (!machine.getIpAddress().equals(add.getIpAddress())
                            || !machine.getNetmask().equals(add.getNetmask())
                            || !machine.getGateway().equals(add.getGateway())
                            || !machine.getNameServer().equals(add.getNameServer()))) {
                machine.setApplyYn("N");
            }

            updateAdditionalInfo(machine);
        }

        logger.debug("[UPDATE_MACHINE] 2. update machine additional info.");

        if (StringUtils.isNotEmpty(machine.getHostName()) && !machine.getHostName().equals(m.getHostName())) {
            // Agent Running ??  ShellAction agent? chhost.sh ? 
            // Agent Down ??  machine_additional_info_tbl? ?? ? Running ?   HostName? ?.
            if (StringUtils.isNotEmpty(m.getIpAddr()) && peacockTransmitter.isActive(machine.getMachineId())) {
                try {
                    // /etc/hosts ?? ? ipAddress  Machine? IP?  ? IP? ?.
                    String ipAddress = null;

                    if (StringUtils.isNotEmpty(machine.getIpAddress())) {
                        ipAddress = machine.getIpAddress();
                    } else {
                        ipAddress = m.getIpAddr();
                    }

                    ProvisioningCommandMessage cmdMsg = new ProvisioningCommandMessage();
                    cmdMsg.setAgentId(machine.getMachineId());
                    cmdMsg.setBlocking(true);

                    int sequence = 0;
                    Command command = new Command("SET_HOSTNAME");

                    ShellAction action = new ShellAction(sequence++);
                    action.setCommand("sh");
                    action.addArguments("chhost.sh");
                    action.addArguments(ipAddress);
                    action.addArguments(machine.getHostName());
                    command.addAction(action);

                    cmdMsg.addCommand(command);

                    PeacockDatagram<AbstractMessage> datagram = new PeacockDatagram<AbstractMessage>(cmdMsg);
                    peacockTransmitter.sendMessage(datagram);

                    hostnameChanged = true;
                } catch (Exception e) {
                    // HostName ? ???  IP ?   ??  .
                    logger.error("Unhandled exception has occurred while change hostname.", e);
                }
            }
        }

        logger.debug("[UPDATE_MACHINE] 3. execute command to change hostname.");

        //   IP ? , Agent Running ??,  IP    IP  ? .
        if (StringUtils.isNotEmpty(machine.getIpAddress()) && peacockTransmitter.isActive(machine.getMachineId())
                && (!machine.getIpAddress().equals(add.getIpAddress())
                        || !machine.getNetmask().equals(add.getNetmask())
                        || !machine.getGateway().equals(add.getGateway())
                        || !machine.getNameServer().equals(add.getNameServer()))) {
            machine.setIpAddr(m.getIpAddr());
            applyStaticIp(machine);
        } else {
            if (hostnameChanged) {
                // IP  ? hostname ?  peacock-agent restart .
                sendCommand(getMachine(machine.getMachineId()), "service peacock-agent restart");
                // Thread Sleep  ? DB Commit? ? ? ? Agent restart   hostname  .
                // ? hostname? ?  controller? Thread.sleep(3000)?  ? Agent? ? ?? ??? .
                //Thread.sleep(3000);
            }
        }

        logger.debug("[UPDATE_MACHINE] 4. finish updateMachine()");

        return hostnameChanged;
    }

    public MachineDto getAdditionalInfo(String machineId) {
        return machineDao.getAdditionalInfo(machineId);
    }

    public void insertAdditionalInfo(MachineDto machine) {
        machineDao.insertAdditionalInfo(machine);
    }

    public void updateAdditionalInfo(MachineDto machine) {
        machineDao.updateAdditionalInfo(machine);
    }

    public void agentRestart(String machineId) throws Exception {
        sendCommand(getMachine(machineId), "service peacock-agent restart");
    }

    public void agentStart(String machineId) throws Exception {
        sendCommand(getMachine(machineId), "service peacock-agent start");
    }

    public void agentStop(String machineId) throws Exception {
        sendCommand(getMachine(machineId), "service peacock-agent stop");
    }

    private void sendCommand(MachineDto machine, String command) throws Exception {
        TargetHost targetHost = new TargetHost();
        targetHost.setHost(machine.getIpAddr());
        targetHost.setPort(Integer.parseInt(machine.getSshPort()));
        targetHost.setUsername(machine.getSshUsername());
        targetHost.setPassword(machine.getSshPassword());
        targetHost.setKeyfile(machine.getSshKeyFile());

        String result = SshExecUtil.executeCommand(targetHost, command);

        logger.debug("Command : [{}], Result : [{}]", command, result);
    }

    public void applyStaticIp(MachineDto machine) throws Exception {
        // Static IP ? 
        boolean result = false;

        // 1. /etc/sysconfig/network-scripts/ifcfg-eth0 ?? ? ? .
        StringBuilder ifcfg = new StringBuilder();
        ifcfg.append("DEVICE=eth0").append("\n").append("BOOTPROTO=static").append("\n").append("ONBOOT=yes")
                .append("\n").append("IPADDR=").append(machine.getIpAddress()).append("\n").append("NETMASK=")
                .append(machine.getNetmask()).append("\n").append("GATEWAY=").append(machine.getGateway())
                .append("\n");

        // 2. /etc/resolv.conf ?? ? ? .
        StringBuilder nameserver = new StringBuilder();

        if (machine.getNameServer() != null) {
            String[] servers = machine.getNameServer().split(",");
            int seq = 1;
            for (String server : servers) {
                nameserver.append("nameserver ").append(server).append("\n");
                ifcfg.append("DNS").append(seq++).append("=").append(server).append("\n");
            }
        }

        logger.debug("ifcfg-etho : [{}], resolv.conf : [{}]", ifcfg.toString(), nameserver.toString());

        // 3. ifcnf-eth0, resolv.conf ?? .
        ProvisioningCommandMessage cmdMsg = new ProvisioningCommandMessage();
        cmdMsg.setAgentId(machine.getMachineId());
        //cmdMsg.setBlocking(true);

        int sequence = 0;
        Command command = new Command("SET_STATIC_IP_ifcfg-eth0");

        FileWriteAction fwAction = new FileWriteAction(sequence++);
        fwAction.setContents(ifcfg.toString());
        fwAction.setFileName("/etc/sysconfig/network-scripts/ifcfg-eth0");
        command.addAction(fwAction);
        cmdMsg.addCommand(command);

        PeacockDatagram<AbstractMessage> datagram = new PeacockDatagram<AbstractMessage>(cmdMsg);
        peacockTransmitter.sendMessage(datagram);

        // nameserver   ?   .
        if (StringUtils.isNotEmpty(nameserver.toString())) {
            cmdMsg = new ProvisioningCommandMessage();
            cmdMsg.setAgentId(machine.getMachineId());
            //cmdMsg.setBlocking(true);

            sequence = 0;
            command = new Command("SET_STATIC_IP_resolv.conf");

            logger.debug("[{}] will be saved to /etc/resolv.conf", nameserver.toString());

            fwAction = new FileWriteAction(sequence++);
            fwAction.setContents(nameserver.toString());
            fwAction.setFileName("/etc/resolv.conf");
            command.addAction(fwAction);
            cmdMsg.addCommand(command);

            datagram = new PeacockDatagram<AbstractMessage>(cmdMsg);
            peacockTransmitter.sendMessage(datagram);
        }

        // PeacockServerHandler? channelRead0() ?  FileWriteAction()? Blocking ?   Block?   .
        // ? Non-Block ?    ?? ? ?.
        TargetHost targetHost = new TargetHost();
        targetHost.setHost(machine.getIpAddr());
        targetHost.setPort(Integer.parseInt(machine.getSshPort()));
        targetHost.setUsername(machine.getSshUsername());
        targetHost.setPassword(machine.getSshPassword());
        targetHost.setKeyfile(machine.getSshKeyFile());

        String output1 = null, output2 = null;
        int retryCnt1 = 0, retryCnt2 = 0;
        while (retryCnt1++ < 10) {
            output1 = SshExecUtil.executeCommand(targetHost, "cat /etc/sysconfig/network-scripts/ifcfg-eth0");

            if (output1.indexOf("IPADDR=" + machine.getIpAddress()) >= 0) {
                // 4. network  ?.
                TargetHost th1 = new TargetHost();
                th1.setHost(machine.getIpAddr());
                th1.setPort(Integer.parseInt(machine.getSshPort()));
                th1.setUsername(machine.getSshUsername());
                th1.setPassword(machine.getSshPassword());
                th1.setKeyfile(machine.getSshKeyFile());

                new NetworkRestarter(th1).start();

                targetHost.setHost(machine.getIpAddress());
                while (retryCnt2++ < 30) {
                    try {
                        output2 = SshExecUtil.executeCommand(targetHost, "ifconfig");

                        if (output2.indexOf(machine.getIpAddress()) >= 0) {
                            TargetHost th2 = new TargetHost();
                            th2.setHost(machine.getIpAddress());
                            th2.setPort(Integer.parseInt(machine.getSshPort()));
                            th2.setUsername(machine.getSshUsername());
                            th2.setPassword(machine.getSshPassword());
                            th2.setKeyfile(machine.getSshKeyFile());

                            // 5. Peacock Agent ?.
                            machine.setIpAddr(machine.getIpAddress());

                            new AgentRestarter(th2).start();

                            // 6. machine_additional_info_tbl? apply_yn ? ?? . 
                            machineDao.applyStaticIp(machine.getMachineId());

                            // 7. Agent ?  Channel? .
                            peacockTransmitter.channelClose(machine.getMachineId());

                            result = true;
                            break;
                        }

                        Thread.sleep(1000);
                    } catch (Exception e) {
                        // service network restart ?  ? IP ifconfig ?   .(JSchException)
                        // ignore...
                    }
                }

                break;
            }

            Thread.sleep(1000);
        }

        if (!result) {
            throw new Exception("static ip set has failed.");
        }
    }
}
//end of MachineService.java

class NetworkRestarter extends Thread {
    protected final Logger logger = LoggerFactory.getLogger(NetworkRestarter.class);

    private TargetHost targetHost;

    public NetworkRestarter(TargetHost targetHost) {
        this.targetHost = targetHost;
    }

    @Override
    public void run() {
        logger.debug("[targetHost in NetworkRestarter] : [{}]", targetHost.toString());

        try {
            String command = "service network restart";
            String result = SshExecUtil.executeCommand(targetHost, command);
            logger.debug("Command : [{}], Result : [{}]", command, result);
        } catch (IOException e) {
            logger.error("Unhandled exception has occurred.", e);
        }
    }
}

class AgentRestarter extends Thread {
    protected final Logger logger = LoggerFactory.getLogger(AgentRestarter.class);

    private TargetHost targetHost;

    public AgentRestarter(TargetHost targetHost) {
        this.targetHost = targetHost;
    }

    @Override
    public void run() {
        logger.debug("[targetHost in AgentRestarter] : [{}]", targetHost.toString());

        try {
            String command = "service peacock-agent restart";
            String result = SshExecUtil.executeCommand(targetHost, command);
            logger.debug("Command : [{}], Result : [{}]", command, result);
        } catch (IOException e) {
            logger.error("Unhandled exception has occurred.", e);
        }
    }
}