jp.primecloud.auto.process.vmware.VmwareProcessClient.java Source code

Java tutorial

Introduction

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

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import jp.primecloud.auto.exception.AutoException;
import jp.primecloud.auto.util.MessageUtils;
import jp.primecloud.auto.vmware.VmwareClient;
import com.vmware.vim25.AlreadyExists;
import com.vmware.vim25.CustomFieldDef;
import com.vmware.vim25.CustomizationSpec;
import com.vmware.vim25.DuplicateName;
import com.vmware.vim25.GuestInfo;
import com.vmware.vim25.GuestNicInfo;
import com.vmware.vim25.HostNetworkPolicy;
import com.vmware.vim25.HostPortGroupConfig;
import com.vmware.vim25.HostPortGroupSpec;
import com.vmware.vim25.InvalidArgument;
import com.vmware.vim25.NetIpConfigInfoIpAddress;
import com.vmware.vim25.NotFound;
import com.vmware.vim25.OptionValue;
import com.vmware.vim25.TaskInfo;
import com.vmware.vim25.TaskInfoState;
import com.vmware.vim25.VirtualDevice;
import com.vmware.vim25.VirtualDeviceConfigSpec;
import com.vmware.vim25.VirtualDeviceConfigSpecFileOperation;
import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
import com.vmware.vim25.VirtualDeviceConnectInfo;
import com.vmware.vim25.VirtualDisk;
import com.vmware.vim25.VirtualDiskFlatVer2BackingInfo;
import com.vmware.vim25.VirtualMachineCloneSpec;
import com.vmware.vim25.VirtualMachineConfigSpec;
import com.vmware.vim25.VirtualMachineGuestState;
import com.vmware.vim25.VirtualMachinePowerState;
import com.vmware.vim25.VirtualMachineRelocateSpec;
import com.vmware.vim25.VirtualMachineRuntimeInfo;
import com.vmware.vim25.VirtualMachineToolsRunningStatus;
import com.vmware.vim25.VirtualMachineToolsVersionStatus;
import com.vmware.vim25.VirtualSCSIController;
import com.vmware.vim25.mo.ComputeResource;
import com.vmware.vim25.mo.CustomFieldsManager;
import com.vmware.vim25.mo.Datacenter;
import com.vmware.vim25.mo.Datastore;
import com.vmware.vim25.mo.FileManager;
import com.vmware.vim25.mo.Folder;
import com.vmware.vim25.mo.HostNetworkSystem;
import com.vmware.vim25.mo.HostSystem;
import com.vmware.vim25.mo.ManagedEntity;
import com.vmware.vim25.mo.ResourcePool;
import com.vmware.vim25.mo.Task;
import com.vmware.vim25.mo.VirtualMachine;

/**
 * <p>
 * TODO: 
 * </p>
 *
 */
public class VmwareProcessClient {

    protected Log log = LogFactory.getLog(getClass());

    protected VmwareClient vmwareClient;

    protected Long platformNo;

    public VmwareProcessClient(VmwareClient vmwareClient, Long platformNo) {
        this.vmwareClient = vmwareClient;
        this.platformNo = platformNo;
    }

    public VmwareClient getVmwareClient() {
        return vmwareClient;
    }

    public Long getPlatformNo() {
        return platformNo;
    }

    protected VirtualMachine getVirtualMachine(String machineName) {
        VirtualMachine machine = vmwareClient.search(VirtualMachine.class, machineName);
        if (machine == null) {
            // ??????
            throw new AutoException("EPROCESS-000501", machineName);
        }

        return machine;
    }

    public void cloneVM(String machineName, String templateName, String computeResourceName,
            String resourcePoolName, String datastoreName) {
        // ?????
        VirtualMachine machine = vmwareClient.search(VirtualMachine.class, machineName);
        if (machine != null) {
            return;
        }

        // ??
        VirtualMachine templateMachine = getVirtualMachine(templateName);

        // ?
        VirtualMachineCloneSpec cloneSpec = createCloneSpec(computeResourceName, resourcePoolName, datastoreName);

        // 
        // TODO: ???
        Folder vmFolder = vmwareClient.search(Folder.class, "vm");

        // ?
        Task task;
        try {
            task = templateMachine.cloneVM_Task(vmFolder, machineName, cloneSpec);
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000502", e, machineName);
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100421", machineName, templateName));
        }

        // ?????
        try {
            task.waitForTask();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000502", e, machineName);
        } catch (InterruptedException ignore) {
        }

        // ??
        TaskInfo taskInfo;
        try {
            taskInfo = task.getTaskInfo();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000502", e, machineName);
        }

        if (taskInfo.getState() != TaskInfoState.success) {
            // ?????
            AutoException exception = new AutoException("EPROCESS-000502", machineName);
            if (taskInfo.getError() != null) {
                exception.addDetailInfo(ReflectionToStringBuilder.toString(taskInfo.getError().getFault()));
                exception.addDetailInfo(taskInfo.getError().getLocalizedMessage());
            }
            throw exception;
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100422", machineName, templateName));
        }
    }

    protected VirtualMachineCloneSpec createCloneSpec(String computeResourceName, String resourcePoolName,
            String datastoreName) {
        VirtualMachineRelocateSpec relocateSpec = new VirtualMachineRelocateSpec();

        // ComputeResource
        ComputeResource computeResource = vmwareClient.search(ComputeResource.class, computeResourceName);
        if (computeResource == null) {
            // ComputeResource??????
            throw new AutoException("EPROCESS-000503", computeResourceName);
        }

        // ResourcePool
        if (StringUtils.isEmpty(resourcePoolName)) {
            resourcePoolName = "Resources";
        }
        ResourcePool resourcePool = vmwareClient.search(computeResource, ResourcePool.class, resourcePoolName);
        if (resourcePool == null) {
            // ResourcePool??????
            throw new AutoException("EPROCESS-000504", resourcePoolName);
        }
        relocateSpec.setPool(resourcePool.getMOR());

        // Datastore
        if (StringUtils.isNotEmpty(datastoreName)) {
            // ?????
            Datastore datastore = vmwareClient.search(Datastore.class, datastoreName);
            if (datastore == null) {
                // ??????
                throw new AutoException("EPROCESS-000505", datastoreName);
            }
            relocateSpec.setDatastore(datastore.getMOR());
        }

        VirtualMachineCloneSpec cloneSpec = new VirtualMachineCloneSpec();
        cloneSpec.setLocation(relocateSpec);
        cloneSpec.setPowerOn(false);
        cloneSpec.setTemplate(false);

        return cloneSpec;
    }

    public void powerOnVM(String machineName) {
        // VirtualMachine
        VirtualMachine machine = getVirtualMachine(machineName);

        // ???
        VirtualMachineRuntimeInfo runtimeInfo = machine.getRuntime();
        if (runtimeInfo.getPowerState() == VirtualMachinePowerState.poweredOn) {
            return;
        }

        // ?
        Task task;
        try {
            task = machine.powerOnVM_Task(null);
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000506", e, machineName);
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100411", machineName));
        }

        // ????
        try {
            task.waitForTask();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000506", e, machineName);
        } catch (InterruptedException ignore) {
        }

        // ??
        TaskInfo taskInfo;
        try {
            taskInfo = task.getTaskInfo();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000506", e, machineName);
        }

        if (taskInfo.getState() != TaskInfoState.success) {
            // ?????
            AutoException exception = new AutoException("EPROCESS-000506", machineName);
            if (taskInfo.getError() != null) {
                exception.addDetailInfo(ReflectionToStringBuilder.toString(taskInfo.getError().getFault()));
                exception.addDetailInfo(taskInfo.getError().getLocalizedMessage());
            }
            throw exception;
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100412", machineName));
        }
    }

    public void powerOffVM(String machineName) {
        // VirtualMachine
        VirtualMachine machine = getVirtualMachine(machineName);

        // ???
        VirtualMachineRuntimeInfo runtimeInfo = machine.getRuntime();
        if (runtimeInfo.getPowerState() == VirtualMachinePowerState.poweredOff) {
            return;
        }

        // ?
        Task task;
        try {
            task = machine.powerOffVM_Task();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000507", e, machineName);
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100413", machineName));
        }

        // ????
        try {
            task.waitForTask();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000507", e, machineName);
        } catch (InterruptedException ignore) {
        }

        // ??
        TaskInfo taskInfo;
        try {
            taskInfo = task.getTaskInfo();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000507", e, machineName);
        }

        if (taskInfo.getState() != TaskInfoState.success) {
            // ?????
            AutoException exception = new AutoException("EPROCESS-000507", machineName);
            if (taskInfo.getError() != null) {
                exception.addDetailInfo(ReflectionToStringBuilder.toString(taskInfo.getError().getFault()));
                exception.addDetailInfo(taskInfo.getError().getLocalizedMessage());
            }
            throw exception;
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100414", machineName));
        }
    }

    public void shutdownGuest(String machineName) {
        // VirtualMachine
        VirtualMachine machine = getVirtualMachine(machineName);

        // ???
        VirtualMachineRuntimeInfo runtimeInfo = machine.getRuntime();
        if (runtimeInfo.getPowerState() == VirtualMachinePowerState.poweredOff) {
            return;
        }

        // ?
        try {
            machine.shutdownGuest();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000519", e, machineName);
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100415", machineName));
        }

        // ????
        waitForStopped(machineName);

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100416", machineName));
        }
    }

    public void destroyVM(String machineName) {
        // VirtualMachine
        VirtualMachine machine = getVirtualMachine(machineName);

        // ?
        Task task;
        try {
            task = machine.destroy_Task();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000508", e, machineName);
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100423", machineName));
        }

        // ????
        try {
            task.waitForTask();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000508", e, machineName);
        } catch (InterruptedException ignore) {
        }

        // ??
        TaskInfo taskInfo;
        try {
            taskInfo = task.getTaskInfo();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000508", e, machineName);
        }

        if (taskInfo.getState() != TaskInfoState.success) {
            // ?????
            AutoException exception = new AutoException("EPROCESS-000508", machineName);
            if (taskInfo.getError() != null) {
                exception.addDetailInfo(ReflectionToStringBuilder.toString(taskInfo.getError().getFault()));
                exception.addDetailInfo(taskInfo.getError().getLocalizedMessage());
            }
            throw exception;
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100424", machineName));
        }
    }

    public void changeResourceVM(String machineName, Integer cpu, Long memory) {
        // VirtualMachine
        VirtualMachine machine = getVirtualMachine(machineName);

        // 
        VirtualMachineConfigSpec configSpec = new VirtualMachineConfigSpec();
        configSpec.setNumCPUs(cpu);
        configSpec.setMemoryMB(memory);

        // 
        Task task;
        try {
            task = machine.reconfigVM_Task(configSpec);
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000513", e, machineName);
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100433", machineName));
        }

        // ????
        try {
            task.waitForTask();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000513", e, machineName);
        } catch (InterruptedException ignore) {
        }

        // ??
        TaskInfo taskInfo;
        try {
            taskInfo = task.getTaskInfo();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000513", e, machineName);
        }

        if (taskInfo.getState() != TaskInfoState.success) {
            // ??????
            AutoException exception = new AutoException("EPROCESS-000513", machineName);
            if (taskInfo.getError() != null) {
                exception.addDetailInfo(ReflectionToStringBuilder.toString(taskInfo.getError().getFault()));
                exception.addDetailInfo(taskInfo.getError().getLocalizedMessage());
            }
            throw exception;
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100434", machineName));
        }
    }

    public void setExtraConfigVM(String machineName, Map<String, Object> extraConfigs) {
        // VirtualMachine
        VirtualMachine machine = getVirtualMachine(machineName);

        // ExtraConfig?
        List<OptionValue> optionValues = new ArrayList<OptionValue>();
        for (Map.Entry<String, Object> entry : extraConfigs.entrySet()) {
            OptionValue optionValue = new OptionValue();
            optionValue.setKey(entry.getKey());
            optionValue.setValue(entry.getValue());
            optionValues.add(optionValue);
        }

        // 
        VirtualMachineConfigSpec configSpec = new VirtualMachineConfigSpec();
        configSpec.setExtraConfig(optionValues.toArray(new OptionValue[optionValues.size()]));

        // ?
        Task task;
        try {
            task = machine.reconfigVM_Task(configSpec);
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000523", e, machineName);
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100435", machineName));
        }

        // ????
        try {
            task.waitForTask();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000523", e, machineName);
        } catch (InterruptedException ignore) {
        }

        // ??
        TaskInfo taskInfo;
        try {
            taskInfo = task.getTaskInfo();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000523", e, machineName);
        }

        if (taskInfo.getState() != TaskInfoState.success) {
            // ?????
            AutoException exception = new AutoException("EPROCESS-000523", machineName);
            if (taskInfo.getError() != null) {
                exception.addDetailInfo(ReflectionToStringBuilder.toString(taskInfo.getError().getFault()));
                exception.addDetailInfo(taskInfo.getError().getLocalizedMessage());
            }
            throw exception;
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100436", machineName));
        }
    }

    public void waitForRunning(String machineName) {
        VirtualMachine machine = getVirtualMachine(machineName);

        // ?
        long startTime = System.currentTimeMillis();
        while (true) {
            // 15???????????
            if (System.currentTimeMillis() - startTime > 15 * 60 * 1000L) {
                throw new AutoException("EPROCESS-000531", machineName);
            }

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

            // ?????
            if (machine.getRuntime().getPowerState() != VirtualMachinePowerState.poweredOn) {
                throw new AutoException("EPROCESS-000530", machineName);
            }

            // ?
            GuestInfo guestInfo = machine.getGuest();

            if (log.isDebugEnabled()) {
                log.debug(jp.primecloud.auto.util.StringUtils.reflectToString(guestInfo));
            }

            // VMware Tools??????
            if (VirtualMachineToolsVersionStatus.guestToolsNotInstalled.toString()
                    .equals(guestInfo.getToolsVersionStatus2())) {
                throw new AutoException("EPROCESS-000509", machineName);
            }

            // VMware Tools??????
            if (!VirtualMachineToolsRunningStatus.guestToolsRunning.toString()
                    .equals(guestInfo.getToolsRunningStatus())) {
                continue;
            }

            // ??????
            if (!VirtualMachineGuestState.running.toString().equals(guestInfo.getGuestState())) {
                continue;
            }

            // ?????????
            if (guestInfo.getNet() == null) {
                continue;
            }

            // ???IP??????
            int count = 0;
            for (GuestNicInfo nicInfo : guestInfo.getNet()) {
                // NIC?IPv4??
                NetIpConfigInfoIpAddress[] tmpAddresses = nicInfo.getIpConfig().getIpAddress();
                if (tmpAddresses == null) {
                    continue;
                }
                String ipAddress = null;
                for (NetIpConfigInfoIpAddress tmpAdress : tmpAddresses) {
                    try {
                        InetAddress inetAddress = InetAddress.getByName(tmpAdress.getIpAddress());
                        if (inetAddress instanceof Inet4Address) {
                            ipAddress = tmpAdress.getIpAddress();
                            break;
                        }
                    } catch (UnknownHostException ignore) {
                    }
                }

                if (ipAddress != null && !StringUtils.startsWith(ipAddress, "169.254.")) {
                    count++;
                }
            }
            if (count != guestInfo.getNet().length) {
                continue;
            }

            break;
        }
    }

    public void waitForStopped(String machineName) {
        VirtualMachine machine = getVirtualMachine(machineName);

        // ??
        while (true) {
            try {
                Thread.sleep(30 * 1000L);
            } catch (InterruptedException ignore) {
            }

            VirtualMachineRuntimeInfo runtimeInfo = machine.getRuntime();

            if (runtimeInfo.getPowerState() == VirtualMachinePowerState.poweredOff) {
                break;
            }
        }
    }

    public void addNetwork(String hostSystemName, String portGroupName, Integer vlanId, String vswitchName) {
        // HostSystem
        HostSystem hostSystem = vmwareClient.search(HostSystem.class, hostSystemName);
        if (hostSystem == null) {
            // ??????
            throw new AutoException("EPROCESS-000524", hostSystem);
        }

        // HostNetworkSystem
        HostNetworkSystem networkSystem;
        try {
            networkSystem = hostSystem.getHostNetworkSystem();
        } catch (RemoteException e) {
            throw new RuntimeException(e);
        }

        // PortGroup?HostSystem????????
        boolean isExist = false;
        for (HostPortGroupConfig config : networkSystem.getNetworkConfig().getPortgroup()) {
            if (StringUtils.equalsIgnoreCase(portGroupName, config.getSpec().getName())) {
                isExist = true;
                break;
            }
        }

        // PortGroup?????
        if (isExist) {
            return;
        }

        // PortGroup??
        HostPortGroupSpec portGroupSpec = new HostPortGroupSpec();
        portGroupSpec.setName(portGroupName);
        if (vlanId != null) {
            portGroupSpec.setVlanId(vlanId);
        }
        portGroupSpec.setVswitchName(vswitchName);
        portGroupSpec.setPolicy(new HostNetworkPolicy());

        try {
            networkSystem.addPortGroup(portGroupSpec);
        } catch (AlreadyExists ignore) {
            // ???????????????
            return;
        } catch (RemoteException e) {
            AutoException exception = new AutoException("EPROCESS-000520", e, portGroupName);
            exception.addDetailInfo(jp.primecloud.auto.util.StringUtils.reflectToString(portGroupSpec));
            throw exception;
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100441", hostSystem.getName(), portGroupName));
        }
    }

    public void removeNetwork(String hostSystemName, String portGroupName) {
        // HostSystem
        HostSystem hostSystem = vmwareClient.search(HostSystem.class, hostSystemName);
        if (hostSystem == null) {
            // ??????
            throw new AutoException("EPROCESS-000524", hostSystem);
        }

        // HostNetworkSystem
        HostNetworkSystem networkSystem;
        try {
            networkSystem = hostSystem.getHostNetworkSystem();
        } catch (RemoteException e) {
            throw new RuntimeException(e);
        }

        // PortGroup?HostSystem????????
        boolean isExist = false;
        for (HostPortGroupConfig config : networkSystem.getNetworkConfig().getPortgroup()) {
            if (StringUtils.equalsIgnoreCase(portGroupName, config.getSpec().getName())) {
                isExist = true;
                break;
            }
        }

        // PortGroup??????
        if (!isExist) {
            return;
        }

        // PortGroup?
        try {
            networkSystem.removePortGroup(portGroupName);
        } catch (NotFound ignore) {
            // ??????????????
            return;
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000521", e, portGroupName);
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100442", hostSystem.getName(), portGroupName));
        }
    }

    public VirtualDisk attachDisk(String machineName, Integer scsiId, Integer size, String fileName) {
        // VirtualMachine
        VirtualMachine machine = getVirtualMachine(machineName);

        // ???????
        boolean existDisk = StringUtils.isEmpty(fileName) ? false : true;

        // ??
        VirtualDisk disk;
        if (!existDisk) {
            // ?????
            disk = newDisk(machine, scsiId, size);
        } else {
            // ???
            disk = reuseDisk(machine, scsiId, fileName);
        }

        // ??
        VirtualDeviceConfigSpec diskSpec = new VirtualDeviceConfigSpec();
        diskSpec.setOperation(VirtualDeviceConfigSpecOperation.add);
        if (!existDisk) {
            diskSpec.setFileOperation(VirtualDeviceConfigSpecFileOperation.create);
        }
        diskSpec.setDevice(disk);

        VirtualMachineConfigSpec configSpec = new VirtualMachineConfigSpec();
        configSpec.setDeviceChange(new VirtualDeviceConfigSpec[] { diskSpec });

        // ??
        Task task;
        try {
            task = machine.reconfigVM_Task(configSpec);
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000515", e, machineName);
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100451", machineName));
        }

        // ?????
        try {
            task.waitForTask();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000515", e, machineName);
        } catch (InterruptedException ignore) {
        }

        // ??
        TaskInfo taskInfo;
        try {
            taskInfo = task.getTaskInfo();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000515", e, machineName);
        }

        if (taskInfo.getState() != TaskInfoState.success) {
            // ??????
            AutoException exception = new AutoException("EPROCESS-000515", machineName);
            if (taskInfo.getError() != null) {
                exception.addDetailInfo(ReflectionToStringBuilder.toString(taskInfo.getError().getFault()));
                exception.addDetailInfo(taskInfo.getError().getLocalizedMessage());
            }
            throw exception;
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100452", machineName));
        }

        return getVirtualDisk(machine, scsiId);
    }

    protected VirtualDisk newDisk(VirtualMachine machine, Integer scsiId, Integer size) {
        // SCSI?
        VirtualSCSIController scsiController = getSCSIController(machine);

        // ??
        VirtualDisk machineDisk = getVirtualDisk(machine, 0);
        VirtualDiskFlatVer2BackingInfo machieBackingInfo = VirtualDiskFlatVer2BackingInfo.class
                .cast(machineDisk.getBacking());

        // VirtualDisk
        VirtualDisk disk = new VirtualDisk();
        disk.setUnitNumber(scsiId);
        disk.setCapacityInKB(size * 1024L * 1024L);
        disk.setControllerKey(scsiController.getKey());

        // VirtualDiskFlatVer2BackingInfo
        VirtualDiskFlatVer2BackingInfo backingInfo = new VirtualDiskFlatVer2BackingInfo();
        backingInfo.setDatastore(null);
        backingInfo.setFileName("");
        backingInfo.setDiskMode("persistent");
        backingInfo.setSplit(false);
        backingInfo.setEagerlyScrub(false);
        backingInfo.setThinProvisioned(machieBackingInfo.getThinProvisioned());
        backingInfo.setWriteThrough(false);
        disk.setBacking(backingInfo);

        // VirtualDeviceConnectInfo
        VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
        connectInfo.setAllowGuestControl(false);
        connectInfo.setStartConnected(true);
        connectInfo.setConnected(true);
        disk.setConnectable(connectInfo);

        return disk;
    }

    protected VirtualDisk reuseDisk(VirtualMachine machine, Integer scsiId, String fileName) {
        // SCSI?
        VirtualSCSIController scsiController = getSCSIController(machine);

        // ??
        VirtualDisk machineDisk = getVirtualDisk(machine, 0);
        VirtualDiskFlatVer2BackingInfo machieBackingInfo = VirtualDiskFlatVer2BackingInfo.class
                .cast(machineDisk.getBacking());

        // VirtualDisk
        VirtualDisk disk = new VirtualDisk();
        disk.setUnitNumber(scsiId);
        disk.setControllerKey(scsiController.getKey());

        // VirtualDiskFlatVer2BackingInfo
        VirtualDiskFlatVer2BackingInfo backingInfo = new VirtualDiskFlatVer2BackingInfo();
        backingInfo.setFileName(fileName);
        backingInfo.setDiskMode("persistent");
        backingInfo.setSplit(false);
        backingInfo.setEagerlyScrub(false);
        backingInfo.setThinProvisioned(machieBackingInfo.getThinProvisioned());
        backingInfo.setWriteThrough(false);
        disk.setBacking(backingInfo);

        // VirtualDeviceConnectInfo
        VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
        connectInfo.setAllowGuestControl(false);
        connectInfo.setStartConnected(true);
        connectInfo.setConnected(true);
        disk.setConnectable(connectInfo);

        return disk;
    }

    protected VirtualSCSIController getSCSIController(VirtualMachine machine) {
        // ??SCSI????BusNumber?0????
        VirtualSCSIController scsiController = null;
        for (VirtualDevice device : machine.getConfig().getHardware().getDevice()) {
            if (device instanceof VirtualSCSIController) {
                VirtualSCSIController scsiController2 = VirtualSCSIController.class.cast(device);
                if (scsiController2.getBusNumber() == 0) {
                    scsiController = scsiController2;
                    break;
                }
            }
        }

        if (scsiController == null) {
            // SCSI??????
            // TODO: SCSI
            throw new AutoException("EPROCESS-000517", 0);
        }

        return scsiController;
    }

    protected VirtualDisk getVirtualDisk(VirtualMachine machine, Integer scsiId) {
        // SCSI?
        VirtualSCSIController scsiController = getSCSIController(machine);

        // SCSI?SCSI ID???
        VirtualDisk disk = null;
        for (VirtualDevice device : machine.getConfig().getHardware().getDevice()) {
            if (device instanceof VirtualDisk) {
                VirtualDisk tmpDisk = VirtualDisk.class.cast(device);
                if (tmpDisk.getControllerKey() != null
                        && tmpDisk.getControllerKey().equals(scsiController.getKey())) {
                    if (tmpDisk.getUnitNumber() != null && tmpDisk.getUnitNumber().equals(scsiId)) {
                        disk = tmpDisk;
                        break;
                    }
                }
            }
        }

        if (disk == null) {
            // VirtualDisk??????
            throw new AutoException("EPROCESS-000518", scsiId);
        }

        return disk;
    }

    public void detachDisk(String machineName, Integer scsiId) {
        // VirtualMachine
        VirtualMachine machine = getVirtualMachine(machineName);

        // ???
        VirtualDisk disk = getVirtualDisk(machine, scsiId);

        // ??
        VirtualDeviceConfigSpec diskSpec = new VirtualDeviceConfigSpec();
        diskSpec.setOperation(VirtualDeviceConfigSpecOperation.remove);
        //diskSpec.setFileOperation(VirtualDeviceConfigSpecFileOperation.destroy);
        diskSpec.setDevice(disk);

        VirtualMachineConfigSpec configSpec = new VirtualMachineConfigSpec();
        configSpec.setDeviceChange(new VirtualDeviceConfigSpec[] { diskSpec });

        // ??
        Task task;
        try {
            task = machine.reconfigVM_Task(configSpec);
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000516", e, machineName);
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100453", machineName));
        }

        // ?????
        try {
            task.waitForTask();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000516", e, machineName);
        } catch (InterruptedException ignore) {
        }

        // ??
        TaskInfo taskInfo;
        try {
            taskInfo = task.getTaskInfo();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000516", e, machineName);
        }

        if (taskInfo.getState() != TaskInfoState.success) {
            // ??????
            AutoException exception = new AutoException("EPROCESS-000516", machineName);
            if (taskInfo.getError() != null) {
                exception.addDetailInfo(ReflectionToStringBuilder.toString(taskInfo.getError().getFault()));
                exception.addDetailInfo(taskInfo.getError().getLocalizedMessage());
            }
            throw exception;
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100454", machineName));
        }
    }

    public void deleteDisk(String datastoreName, String fileName) {
        // Datacenter
        ManagedEntity datacenter = vmwareClient.getRootEntity();

        // Datastore
        Datastore datastore = vmwareClient.search(Datastore.class, datastoreName);
        if (datastore == null) {
            // ??????
            throw new AutoException("EPROCESS-000505", datastoreName);
        }

        // ?
        FileManager fileManager = vmwareClient.getServiceInstance().getFileManager();
        if (fileManager == null) {
            // fileManager???????
            throw new AutoException("EPROCESS-000533");
        }

        try {
            // 
            fileManager.deleteDatastoreFile_Task(fileName, (Datacenter) datacenter);
            // ????????????????
            String flatname;
            flatname = fileName.substring(0, fileName.length() - 5) + "-flat.vmdk";
            fileManager.deleteDatastoreFile_Task(flatname, (Datacenter) datacenter);
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000522", e, fileName);
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100455", fileName));
        }
    }

    public List<CustomFieldDef> getCustomFieldDefs() {
        CustomFieldsManager manager = vmwareClient.getServiceInstance().getCustomFieldsManager();
        CustomFieldDef[] defs = manager.getField();

        List<CustomFieldDef> customFieldDefs = new ArrayList<CustomFieldDef>();
        if (defs != null) {
            for (CustomFieldDef def : defs) {
                customFieldDefs.add(def);
            }
        }
        return customFieldDefs;
    }

    public CustomFieldDef getCustomFieldDef(String name, Class<?> type) {
        CustomFieldsManager manager = vmwareClient.getServiceInstance().getCustomFieldsManager();
        CustomFieldDef[] defs = manager.getField();

        String typeName = type.getSimpleName();

        if (defs != null) {
            for (CustomFieldDef def : defs) {
                if (def.getName().equals(name) && def.getManagedObjectType().equals(typeName)) {
                    return def;
                }
            }
        }
        return null;
    }

    public void addCustomFieldDef(String name, Class<?> type) {
        CustomFieldsManager manager = vmwareClient.getServiceInstance().getCustomFieldsManager();
        CustomFieldDef[] defs = manager.getField();

        String typeName = type.getSimpleName();

        if (defs != null) {
            for (CustomFieldDef def : defs) {
                if (def.getName().equals(name) && def.getManagedObjectType().equals(typeName)) {
                    // ???????
                    return;
                }
            }
        }

        try {
            manager.addCustomFieldDef(name, typeName, null, null);
        } catch (DuplicateName ignore) {
            // ??????????????
            return;
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000525", e, name, typeName);
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100461", name));
        }
    }

    public void removeCustomFieldDef(String name, Class<?> type) {
        CustomFieldsManager manager = vmwareClient.getServiceInstance().getCustomFieldsManager();
        CustomFieldDef[] defs = manager.getField();

        String typeName = type.getSimpleName();

        CustomFieldDef customFieldDef = null;
        if (defs != null) {
            for (CustomFieldDef def : defs) {
                if (def.getName().equals(name) && def.getManagedObjectType().equals(typeName)) {
                    customFieldDef = def;
                }
            }
        }

        if (customFieldDef == null) {
            // ???????
        }

        try {
            manager.removeCustomFieldDef(customFieldDef.getKey());
        } catch (InvalidArgument ignore) {
            // ??????????????
            return;
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000526", e, name, typeName);
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100462", name));
        }
    }

    public void setCustomValue(String machineName, String name, String value) {
        // VirtualMachine
        VirtualMachine machine = getVirtualMachine(machineName);

        // ?
        try {
            machine.setCustomValue(name, value);
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000527", e, machineName, name);
        }

        if (log.isInfoEnabled()) {
            log.info(MessageUtils.getMessage("IPROCESS-100463", machineName, name));
        }
    }

    public void customize(String machineName, CustomizationSpec customSpec) {
        // VirtualMachine
        VirtualMachine machine = getVirtualMachine(machineName);

        // ?
        Task task;
        try {
            task = machine.customizeVM_Task(customSpec);
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000529", e, machineName);
        }

        // ?????
        try {
            task.waitForTask();
        } catch (RemoteException e) {
            throw new AutoException("EPROCESS-000529", e, machineName);
        } catch (InterruptedException ignore) {
        }

        // ??
        TaskInfo taskInfo;
        try {
            taskInfo = task.getTaskInfo();
        } catch (RemoteException e) {
            throw new RuntimeException(e);
        }

        if (taskInfo.getState() != TaskInfoState.success) {
            // ?????
            AutoException exception = new AutoException("EPROCESS-000529", machineName);
            if (taskInfo.getError() != null) {
                exception.addDetailInfo(ReflectionToStringBuilder.toString(taskInfo.getError().getFault()));
                exception.addDetailInfo(taskInfo.getError().getLocalizedMessage());
            }
            throw exception;
        }
    }

}