/******************************************************************************* * Copyright 2012 Urbancode, Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package com.urbancode.terraform.tasks.vmware.util; import java.io.Serializable; import java.net.MalformedURLException; import java.net.URL; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.List; import java.util.UUID; import org.apache.log4j.Logger; import com.vmware.vim25.NotFound; import com.vmware.vim25.VirtualDevice; import com.vmware.vim25.VirtualDeviceConfigSpec; import com.vmware.vim25.VirtualDeviceConfigSpecOperation; import com.vmware.vim25.VirtualEthernetCard; import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo; import com.vmware.vim25.VirtualMachineConfigSpec; import com.vmware.vim25.VirtualMachineToolsStatus; import com.vmware.vim25.mo.ComputeResource; import com.vmware.vim25.mo.Datacenter; 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.Network; import com.vmware.vim25.mo.SearchIndex; import com.vmware.vim25.mo.ServiceInstance; import com.vmware.vim25.mo.Task; import com.vmware.vim25.mo.VirtualMachine; public class VirtualHost implements Serializable { //********************************************************************************************** // CLASS //********************************************************************************************** /** * This class contains utility methods for handling VSphere objects. * It also stores the vSphere ServiceInstance object for connecting to vCenter. * There is a nonzero chance that some of these methods will be refactored in to * CloneTask, NetworkTask, NetworkRefTask, and other classes. */ final static private Logger log = Logger.getLogger(VirtualHost.class); private static final long serialVersionUID = 1L; //********************************************************************************************** // INSTANCE //********************************************************************************************** private ServiceInstance serviceInstance; private String url; private String user; private String password; //---------------------------------------------------------------------------------------------- public VirtualHost(String url, String user, String password) throws RemoteException, MalformedURLException { this.url = url; this.user = user; this.password = password; serviceInstance = new ServiceInstance(new URL(url), user, password, true); } //---------------------------------------------------------------------------------------------- public String getUrl() { return this.url; } //---------------------------------------------------------------------------------------------- public String getUser() { return this.user; } //---------------------------------------------------------------------------------------------- public String getPassword() { return this.password; } //---------------------------------------------------------------------------------------------- public ServiceInstance getServiceInstance() { return this.serviceInstance; } //---------------------------------------------------------------------------------------------- public void close() { serviceInstance.getServerConnection().logout(); } //---------------------------------------------------------------------------------------------- public VirtualEthernetCard getNic(VirtualMachine vm, int nicIndex) throws RemoteException { if (nicIndex < 0) { throw new IllegalArgumentException("Invalid nic index"); } List<VirtualEthernetCard> nics = new ArrayList<VirtualEthernetCard>(); VirtualDevice[] devices = vm.getConfig().getHardware().getDevice(); for (VirtualDevice device : devices) { if (device instanceof VirtualEthernetCard) { nics.add((VirtualEthernetCard) device); } } if (nics.size() < nicIndex) { throw new IllegalArgumentException("Invalid nic index"); } return nics.get(nicIndex); } //---------------------------------------------------------------------------------------------- public List<VirtualEthernetCard> getAllNics(VirtualMachine vm) throws RemoteException { List<VirtualEthernetCard> nics = new ArrayList<VirtualEthernetCard>(); VirtualDevice[] devices = vm.getConfig().getHardware().getDevice(); for (VirtualDevice device : devices) { if (device instanceof VirtualEthernetCard) { nics.add((VirtualEthernetCard) device); } } return nics; } //---------------------------------------------------------------------------------------------- public void attachNic(VirtualMachine vm, VirtualEthernetCard nic, Network network) throws RemoteException, InterruptedException { VirtualEthernetCardNetworkBackingInfo backing = (VirtualEthernetCardNetworkBackingInfo) nic.getBacking(); backing.setDeviceName(network.getName()); backing.setNetwork(network.getMOR()); nic.setBacking(backing); nic.getDeviceInfo().setSummary(network.getName()); VirtualDeviceConfigSpec nicSpec = new VirtualDeviceConfigSpec(); nicSpec.setOperation(VirtualDeviceConfigSpecOperation.edit); nicSpec.setDevice(nic); VirtualDeviceConfigSpec[] configSpecs = new VirtualDeviceConfigSpec[1]; configSpecs[0] = nicSpec; VirtualMachineConfigSpec machineConfigSpec = new VirtualMachineConfigSpec(); machineConfigSpec.setDeviceChange(configSpecs); Task task = vm.reconfigVM_Task(machineConfigSpec); String status = task.waitForTask(); if (!status.equals("success")) { String message = task.getTaskInfo().getError().getLocalizedMessage(); throw new RemoteException("Failed: " + message); } } //---------------------------------------------------------------------------------------------- public void removeSwitch(Path path) throws RemoteException { ComputeResource res = getComputeResource(path.getParent()); HostSystem host = res.getHosts()[0]; HostNetworkSystem networkSystem = host.getHostNetworkSystem(); try { networkSystem.removeVirtualSwitch(path.getName()); } catch (NotFound swallow) { } } //---------------------------------------------------------------------------------------------- public void removePortGroup(Path path) throws RemoteException { ComputeResource res = getComputeResource(path.getParent()); HostSystem host = res.getHosts()[0]; HostNetworkSystem networkSystem = host.getHostNetworkSystem(); try { networkSystem.removePortGroup(path.getName()); } catch (NotFound swallow) { } } //---------------------------------------------------------------------------------------------- public VirtualMachine getVm(UUID vmid) throws RemoteException { SearchIndex searchIndex = serviceInstance.getSearchIndex(); VirtualMachine vm = (VirtualMachine) searchIndex.findByUuid( null, vmid.toString(), true, true); if (vm == null) { throw new NotFound(); } return vm; } //---------------------------------------------------------------------------------------------- public String getVmxPath(VirtualMachine vm) { return vm.getConfig().getFiles().getVmPathName(); } //---------------------------------------------------------------------------------------------- public void waitForIp(VirtualMachine vm) throws RemoteException, InterruptedException { long pollInterval = 3000L; long timeoutInterval = 10L * 60L * 1000L; long start = System.currentTimeMillis(); String address = vm.getGuest().getIpAddress(); while (address == null) { if (System.currentTimeMillis() - start > timeoutInterval) { throw new RemoteException("Timeout waiting for IP"); } Thread.sleep(pollInterval); address = vm.getGuest().getIpAddress(); } assert address != null; } //---------------------------------------------------------------------------------------------- public void waitForIp(UUID vmid) throws RemoteException, InterruptedException { waitForIp(getVm(vmid)); } //---------------------------------------------------------------------------------------------- /** * This method will wait for VM Tools to be running. For example, the machine might * still be booting and thus VM Tools would not be running. * @param vm * @throws RemoteException * @throws InterruptedException */ public void waitForVmtools(VirtualMachine vm) throws RemoteException, InterruptedException { long pollInterval = 3000L; long timeoutInterval = 5L * 60L * 1000L; long start = System.currentTimeMillis(); VirtualMachineToolsStatus toolsStatus = vm.getGuest().getToolsStatus(); while (toolsStatus != VirtualMachineToolsStatus.toolsOk && toolsStatus != VirtualMachineToolsStatus.toolsOld) { if (System.currentTimeMillis() - start > timeoutInterval) { throw new RemoteException("Timeout waiting for vmtools"); } Thread.sleep(pollInterval); toolsStatus = vm.getGuest().getToolsStatus(); } } //---------------------------------------------------------------------------------------------- public void waitForVmtools(UUID vmid) throws RemoteException, InterruptedException { waitForVmtools(getVm(vmid)); } //---------------------------------------------------------------------------------------------- /** * * @param path * @return the ComputerResource associated with the datacenter and host. * @throws RemoteException */ public ComputeResource getComputeResource(Path path) throws RemoteException { ComputeResource result = null; String name = path.getName(); Folder root = serviceInstance.getRootFolder(); Folder folderResult = root; Folder nextFolder = null; //fixed to accomodate datacenters on root folder, need to check if works for nonroot case for (String fName : path.toList()) { for (ManagedEntity e : folderResult.getChildEntity()) { log.trace("ManagedEntity " + e.getName() + " with type " + e.getClass() + " attempting to match " + name); if (e instanceof ComputeResource && e.getName().equals(name)){ result = (ComputeResource) e; break; } if (e instanceof Folder && e.getName().equals(fName)) { nextFolder = (Folder) e; break; } else if (e instanceof Datacenter && e.getName().equals(fName)) { Datacenter datacenter = (Datacenter) e; nextFolder = datacenter.getHostFolder(); break; } } folderResult = nextFolder; nextFolder = null; } if (result == null) { throw new NotFound(); } return result; } //---------------------------------------------------------------------------------------------- public Datacenter getDatacenter(Path path) throws RemoteException { Datacenter result = null; String name = path.getDatacenterName(); Folder root = serviceInstance.getRootFolder(); for (ManagedEntity e : root.getChildEntity()) { if (e instanceof Datacenter && e.getName().equals(name)) { result = (Datacenter) e; break; } } if (result == null) { log.warn("could not find datacenter at beginning of path " + path.toString()); throw new NotFound(); } return result; } //---------------------------------------------------------------------------------------------- public Datacenter getDatacenterFromEnd(Path path) throws RemoteException { Datacenter result = null; String name = path.getName(); Folder folderResult = serviceInstance.getRootFolder(); List<String> folderList = path.getFolders().toList(); Folder nextFolder = null; for (String fName : folderList) { for (ManagedEntity e : folderResult.getChildEntity()) { log.trace("ManagedEntity " + e.getName() + " with type " + e.getClass() + " attempting to match " + name); if (e instanceof Datacenter && e.getName().equals(name)){ result = (Datacenter) e; break; } if (e instanceof Folder && e.getName().equals(fName)) { nextFolder = (Folder) e; break; } } folderResult = nextFolder; nextFolder = null; } if (folderList.isEmpty()) { for (ManagedEntity e : folderResult.getChildEntity()) { log.trace("ManagedEntity " + e.getName() + " with type " + e.getClass() + " attempting to match " + name); if (e instanceof Datacenter && e.getName().equals(name)){ result = (Datacenter) e; break; } } } if (result == null) { log.warn("could not find datacenter at end of path " + path.toString()); throw new NotFound(); } return result; } //---------------------------------------------------------------------------------------------- public Folder getRootFolder() { return serviceInstance.getRootFolder(); } }