/* * 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 extendRootDisk(String machineName, Integer rootSize) { // VirtualMachine VirtualMachine machine = getVirtualMachine(machineName); // ルートディスク VirtualDisk disk = getVirtualDisk(machine, 0); // 指定されたサイズよりも実際のサイズが大きければ、ディスクの拡張を行わない long newCapacityInKB = rootSize.longValue() * 1024 * 1024; if (disk.getCapacityInKB() >= newCapacityInKB) { return; } // 設定変更仕様 disk.setCapacityInKB(newCapacityInKB); VirtualDeviceConfigSpec diskSpec = new VirtualDeviceConfigSpec(); diskSpec.setOperation(VirtualDeviceConfigSpecOperation.edit); 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-000534", e, machineName); } if (log.isInfoEnabled()) { log.info(MessageUtils.getMessage("IPROCESS-100425", machineName, rootSize)); } // 設定が変更されるまで待機 try { task.waitForTask(); } catch (RemoteException e) { throw new AutoException("EPROCESS-000534", e, machineName); } catch (InterruptedException ignore) { } // タスク情報の取得 TaskInfo taskInfo; try { taskInfo = task.getTaskInfo(); } catch (RemoteException e) { throw new AutoException("EPROCESS-000534", e, machineName); } if (taskInfo.getState() != TaskInfoState.success) { // ディスクの設定変更に失敗した場合 AutoException exception = new AutoException("EPROCESS-000534", 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-100426", machineName, rootSize)); } } 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, List<String> networkNames) { 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; } // IPv4アドレスが付いたネットワークアダプタ名を取得 List<String> enableNetworkNames = new ArrayList<String>(); for (GuestNicInfo nicInfo : guestInfo.getNet()) { // 仮想ネットワークアダプタの場合はスキップ if (StringUtils.isEmpty(nicInfo.getNetwork())) { continue; } // 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) { } } // IPアドレスを取得できない、またはリンクローカルのIPアドレスの場合はスキップ if (ipAddress == null || StringUtils.startsWith(ipAddress, "169.254.")) { continue; } enableNetworkNames.add(nicInfo.getNetwork()); } // 指定された全てのネットワークアダプタにIPv4アドレスが付いていること if (!enableNetworkNames.containsAll(networkNames)) { 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; } } }