/** * Copyright (c) 2016 Inria * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * - Christophe Gourdin <christophe.gourdin@inria.fr> * */ package org.occiware.clouddesigner.occi.infrastructure.connector.vmware.utils; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import org.occiware.clouddesigner.occi.infrastructure.connector.vmware.addons.exceptions.VirtualSwitchNotFoundException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.vmware.vim25.Description; import com.vmware.vim25.GuestNicInfo; import com.vmware.vim25.HostIpConfig; import com.vmware.vim25.HostNetworkPolicy; import com.vmware.vim25.HostPortGroup; import com.vmware.vim25.HostPortGroupSpec; import com.vmware.vim25.HostVirtualNicSpec; import com.vmware.vim25.HostVirtualSwitch; import com.vmware.vim25.HostVirtualSwitchConfig; import com.vmware.vim25.HostVirtualSwitchSpec; import com.vmware.vim25.InvalidProperty; import com.vmware.vim25.MethodFault; import com.vmware.vim25.RuntimeFault; import com.vmware.vim25.TaskInfo; import com.vmware.vim25.TaskInfoState; import com.vmware.vim25.VirtualDevice; import com.vmware.vim25.VirtualDeviceBackingInfo; import com.vmware.vim25.VirtualDeviceConfigSpec; import com.vmware.vim25.VirtualDeviceConfigSpecOperation; import com.vmware.vim25.VirtualDeviceConnectInfo; import com.vmware.vim25.VirtualE1000; import com.vmware.vim25.VirtualE1000e; import com.vmware.vim25.VirtualEthernetCard; import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo; import com.vmware.vim25.VirtualHardware; import com.vmware.vim25.VirtualMachineConfigInfo; import com.vmware.vim25.VirtualMachineConfigSpec; import com.vmware.vim25.VirtualPCNet32; import com.vmware.vim25.VirtualVmxnet; import com.vmware.vim25.VirtualVmxnet2; import com.vmware.vim25.VirtualVmxnet3; import com.vmware.vim25.mo.Folder; import com.vmware.vim25.mo.HostNetworkSystem; import com.vmware.vim25.mo.HostSystem; import com.vmware.vim25.mo.InventoryNavigator; import com.vmware.vim25.mo.ManagedEntity; import com.vmware.vim25.mo.Network; import com.vmware.vim25.mo.Task; import com.vmware.vim25.mo.VirtualMachine; /** * Helper for network operations. * * @author Christophe Gourdin - Inria. * */ public class NetworkHelper { private static Logger LOGGER = LoggerFactory.getLogger(NetworkHelper.class); public static final String NETWORK = "Network"; public static final String HOST_NETWORK_SYSTEM = "HostNetworkSystem"; public static final String HOST_FIREWALL_SYSTEM = "HostFirewallSystem"; public static final String HOST_SNMP_SYSTEM = "HostSnmpSystem"; public static final String HOST_SERVICE_SYSTEM = "HostServiceSystem"; public static final String HOST_VMOTION_SYSTEM = "HostVMotionSystem"; public static final String DISTRIBUTED_VSWITCH = "DistributedVirtualSwitch"; public static final String STANDARD_VSWITCH = "HostVirtualSwitch"; // "generated", "manual", "assigned" /** * Warning: these are for mac address. */ public static final String MODE_NETWORK_ADDRESS_GENERATED = "generated"; public static final String MODE_NETWORK_ADDRESS_MANUAL = "manual"; public static final String MODE_NETWORK_ADDRESS_ASSIGNED = "assigned"; /** * Find a list of ethernet device for a vm with the specified * hostnetworkname. * * @param hostNetworkName * @param vm * @return {@link List}{@link VirtualEthernetCard} if none, empty list is * returned. */ public static List<VirtualEthernetCard> findNetDeviceForHostNetName(final String hostNetworkName, VirtualMachine vm) { List<VirtualEthernetCard> vEths = new ArrayList<VirtualEthernetCard>(); VirtualMachineConfigInfo config = vm.getConfig(); VirtualHardware hw = config.getHardware(); VirtualDevice[] devices = hw.getDevice(); for (VirtualDevice device : devices) { if (device instanceof VirtualEthernetCard) { VirtualEthernetCard vEth = (VirtualEthernetCard) device; VirtualDeviceBackingInfo properties = vEth.getBacking(); VirtualEthernetCardNetworkBackingInfo nicBacking = (VirtualEthernetCardNetworkBackingInfo) properties; if (nicBacking != null && nicBacking.getDeviceName().equals(hostNetworkName)) { // Device is in hostNetworkName field. vEths.add(vEth); } } } return vEths; } /** * Find a specific virtual ethernet card on vm for the ethernet card name or * externalId property. * * @param networkAdapterName * @param vm * @return a {@link VirtualEthernetCard} object or null if none is found. */ public static VirtualEthernetCard findVirtualEthernetCardForVM(final String networkAdapterName, final VirtualMachine vm) { VirtualEthernetCard result = null; VirtualEthernetCard vEth = null; String externalId = null; String deviceName = null; if (vm == null) { return result; } VirtualDevice[] vdevices = vm.getConfig().getHardware().getDevice(); if (vdevices == null) { return result; } for (VirtualDevice device : vdevices) { if (device instanceof VirtualEthernetCard) { vEth = (VirtualEthernetCard) device; // Get the name. deviceName = vEth.getDeviceInfo().getLabel(); externalId = vEth.getExternalId(); if (deviceName != null && deviceName.equals(networkAdapterName)) { result = vEth; break; } if (externalId != null && externalId.equals(networkAdapterName)) { result = vEth; break; } } } return result; } /** * Get all virtual ethernet card object for a VM. * * @param vm * @return */ public static List<VirtualEthernetCard> getNetworkAdaptersForVM(String vmName) { List<VirtualEthernetCard> vEths = new ArrayList<VirtualEthernetCard>(); if (vmName == null) { return vEths; } VirtualEthernetCard vEth; Folder rootFolder = VCenterClient.getServiceInstance().getRootFolder(); VirtualMachine vm = VMHelper.findVMForName(rootFolder, vmName); VirtualDevice[] vdevices = vm.getConfig().getHardware().getDevice(); for (VirtualDevice device : vdevices) { if (device instanceof VirtualEthernetCard) { vEth = (VirtualEthernetCard) device; vEths.add(vEth); } } return vEths; } /** * Return the type of virtual device. (E1000, PCnet32, vmxnet etc.) * * @param vEth * @return the network adapter type or "unknown" if newer types. */ public static String getVirtualDeviceAdapterType(VirtualEthernetCard vEth) { String type = null; if (vEth instanceof VirtualE1000) { type = "E1000"; } else if (vEth instanceof VirtualE1000e) { type = "E1000E"; } else if (vEth instanceof VirtualPCNet32) { type = "PCnet32"; } else if (vEth instanceof VirtualVmxnet) { type = "Vmxnet"; } else if (vEth instanceof VirtualVmxnet2) { type = "Vmxnet2"; } else if (vEth instanceof VirtualVmxnet3) { type = "Vmxnet3"; } else { type = "unknown"; } return type; } /** * Check if a nic exist on virtual machine. * * @param networkAdapterName * @param vm * @return true if exist, false otherwise. */ public static boolean isNICExist(String networkAdapterName, VirtualMachine vm) { boolean exist = false; VirtualEthernetCard eth = findVirtualEthernetCardForVM(networkAdapterName, vm); if (eth != null) { exist = true; } return exist; } /** * Check if hostnetwork exist for a name. * * @param hostNetworkName * @param host * @return */ public static boolean isHostNetworkExist(String hostNetworkName, HostSystem host) { boolean exist = false; try { Network[] networks = host.getNetworks(); if (networks != null) { for (Network network : networks) { String hostNetwork = network.getName(); if (hostNetwork.equals(hostNetworkName)) { exist = true; break; } } } } catch (RemoteException ex) { LOGGER.error("Error while reading networks on host: " + host.getName(), ex); LOGGER.error("Message: " + ex.getMessage()); } return exist; } /** * Create device spec for network adapter (nic). * * @param netName * @param nicName * @param mode * ("generated", "manual", "assigned" by VC),this mode set the * mac address. * @param ipAddress * (ex: 192.168.1.1) * @return */ public static VirtualDeviceConfigSpec createNicSpec(String netName, String nicName, String mode, String ipAddress) { // TODO : Set ipAddress manually. via HostVirtualNicSpec see vijava // sample AddVirtualNic..it is for vswitch not the nic for virtual // machine. VirtualDeviceConfigSpec nicSpec = new VirtualDeviceConfigSpec(); nicSpec.setOperation(VirtualDeviceConfigSpecOperation.add); // TODO : Choose adapter type. E1000, pcnet etc. // VirtualEthernetCard nic = new VirtualPCNet32(); VirtualEthernetCard nic = new VirtualE1000(); VirtualEthernetCardNetworkBackingInfo nicBacking = new VirtualEthernetCardNetworkBackingInfo(); nicBacking.setDeviceName(netName); if (mode.equals(MODE_NETWORK_ADDRESS_MANUAL)) { // TODO : Customize macAdress, manual configuration mode. } nic.setAddressType(mode); nic.setBacking(nicBacking); nic.setKey(0); LOGGER.info("Creating Network adapter : " + nicName + " on network: " + netName + " in progress..."); Description info = new Description(); info.setLabel(nicName); info.setSummary(netName); nic.setDeviceInfo(info); nic.setExternalId(nicName); VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo(); connectInfo.setAllowGuestControl(true); connectInfo.setStartConnected(true); connectInfo.setConnected(true); nic.setConnectable(connectInfo); nicSpec.setDevice(nic); return nicSpec; } /** * Create a new VSwitch and create a port group attached. * * @param vSwitchName, * the vSwitch name. * @param portGroupName, * this is here the network name. * @param nbSwitchPort * (default to 8 if nb port = 0). * @param vlanId * : the VLAN id to associate * @param host * : the host real machine * @param macAddress * : if null, mac address is set automatically * @param ipAddress * IP Address to VMKernel. * @param subnetMask * @param dhcpMode * : true dhcp mode, false manual ip addressing mode. * @return * @throws RemoteException * @throws RuntimeFault * @throws InvalidProperty */ public static HostNetworkSystem createVSwitch(String vSwitchName, String portGroupName, int nbSwitchPort, int vlanId, HostSystem host, String macAddress, String ipAddress, String subnetMask, boolean dhcpMode) throws InvalidProperty, RuntimeFault, RemoteException { HostNetworkSystem hns = host.getHostNetworkSystem(); // add a virtual switch HostVirtualSwitchSpec spec = new HostVirtualSwitchSpec(); if (nbSwitchPort == 0) { nbSwitchPort = 8; } spec.setNumPorts(nbSwitchPort); hns.addVirtualSwitch(vSwitchName, spec); // add a port group HostPortGroupSpec hpgs = new HostPortGroupSpec(); hpgs.setName(portGroupName); hpgs.setVlanId(vlanId); // 0 ==> not associated with a VLAN hpgs.setVswitchName(vSwitchName); hpgs.setPolicy(new HostNetworkPolicy()); hns.addPortGroup(hpgs); // add a virtual NIC to VMKernel HostVirtualNicSpec hvns = new HostVirtualNicSpec(); // If a mac address is set. if (macAddress != null) { hvns.setMac(macAddress); } HostIpConfig hic = new HostIpConfig(); hic.setDhcp(dhcpMode); if (!dhcpMode) { if (ipAddress != null) { hic.setIpAddress(ipAddress); } if (subnetMask != null) { hic.setSubnetMask(subnetMask); } } hvns.setIp(hic); String result = hns.addVirtualNic("VMKernel", hvns); LOGGER.info(result); return hns; } /** * Retrieve a hostPortGroup object to get vswitch info and port group info. * * @param host * @param networkName * (portGroupName) * @return a {@link HostPortGroup} if none found, null value is returned. */ public static HostPortGroup findPortGroup(HostSystem host, String networkName) { HostPortGroup portGroupResult = null; try { HostPortGroup[] portGroups = host.getHostNetworkSystem().getNetworkInfo().getPortgroup(); if (portGroups == null) { LOGGER.error("No port group on host: " + host.getName()); return portGroupResult; } for (HostPortGroup portGroup : portGroups) { if (portGroup.getSpec().getName().equals(networkName)) { portGroupResult = portGroup; break; } } } catch (RemoteException ex) { LOGGER.error("Cant find hostPortGroup: " + networkName + " on host: " + host.getName()); LOGGER.error("Message: " + ex.getMessage()); ex.printStackTrace(); } return portGroupResult; } /** * Find a standard vswitch by name on a host system. * * @param host * @param vSwitchName * @return * @throws VirtualSwitchNotFoundException */ public static HostVirtualSwitch findVSwitch(HostSystem host, String vSwitchName) throws VirtualSwitchNotFoundException { HostVirtualSwitch vSwitch = null; try { if (vSwitchName == null) { throw new VirtualSwitchNotFoundException("No virtual switch name defined, cant find the vswitch."); } if (host == null) { throw new VirtualSwitchNotFoundException( "No host defined, cant find the standard virtual switch : " + vSwitchName); } HostVirtualSwitch[] vswitchs = host.getHostNetworkSystem().getNetworkInfo().getVswitch(); if (vswitchs == null) { throw new VirtualSwitchNotFoundException( "The virtual switch : " + vSwitchName + " has not been found on host : " + host.getName()); } for (HostVirtualSwitch standardSwitch : vswitchs) { if (standardSwitch.getName().equals(vSwitchName)) { vSwitch = standardSwitch; break; } } if (vSwitch == null) { throw new VirtualSwitchNotFoundException( "The virtual switch : " + vSwitchName + " has not been found on host : " + host.getName()); } } catch (RemoteException ex) { LOGGER.error("Cant find standard virtual switch"); LOGGER.error("Message: " + ex.getMessage()); ex.printStackTrace(); } return vSwitch; } /** * Action up on network adapter on vm. * * @param vm * @param vEth * @return */ public static boolean up(VirtualMachine vm, VirtualEthernetCard vEth) { boolean result = false; VirtualDeviceConnectInfo connect = vEth.getConnectable(); if (!connect.isConnected()) { connect.setConnected(true); vEth.setConnectable(connect); } // Launch the task. result = launchUpDownTask(vm, vEth, true); return result; } /** * Action down on network adapter on vm. * * @param vm * @param vEth * @return */ public static boolean down(VirtualMachine vm, VirtualEthernetCard vEth) { boolean result = false; // Get connect info. VirtualDeviceConnectInfo connect = vEth.getConnectable(); if (connect.isConnected()) { connect.setConnected(false); vEth.setConnectable(connect); } result = launchUpDownTask(vm, vEth, false); return result; } /** * The the task for disconnection or connection. * * @param vm * @param vEth * @param from * @return true if the task succeed. */ private static boolean launchUpDownTask(VirtualMachine vm, VirtualEthernetCard vEth, boolean from) { boolean result = false; VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); VirtualDeviceConfigSpec nicSpec = new VirtualDeviceConfigSpec(); nicSpec.setOperation(VirtualDeviceConfigSpecOperation.edit); nicSpec.setDevice(vEth); VirtualDeviceConfigSpec[] nicSpecArray = { nicSpec }; vmConfigSpec.setDeviceChange(nicSpecArray); String externalId = vEth.getExternalId(); String name = null; if (externalId == null) { name = vEth.getDeviceInfo().getLabel(); } else { name = externalId; } String status; if (from) { status = "connected"; } else { status = "disconnected"; } // Launch the task. Task task; try { task = vm.reconfigVM_Task(vmConfigSpec); task.waitForTask(); } catch (RemoteException e) { LOGGER.error("Error while " + status + " a network adapter : " + name + " --< from vm : " + vm.getName(), e); LOGGER.error("Message: " + e.getMessage()); return result; } catch (InterruptedException e) { LOGGER.error("Error while " + status + " a network adapter : " + name + " --< from vm : " + vm.getName(), e); LOGGER.error("Message: " + e.getMessage()); return result; } TaskInfo taskInfo; try { taskInfo = task.getTaskInfo(); if (taskInfo.getState() != TaskInfoState.success) { MethodFault fault = taskInfo.getError().getFault(); LOGGER.error( "Error while " + status + " a network adapter : " + name + " --< from vm : " + vm.getName(), fault.detail); LOGGER.error("Fault message: " + fault.getMessage() + fault.getClass().getName()); } else { LOGGER.info("The network : " + name + " is " + status + " from virtual machine : " + vm.getName()); result = true; } } catch (RemoteException e) { LOGGER.error("Error while " + status + " an network adapter : " + name + " --< to vm : " + vm.getName(), e); LOGGER.error("Message : " + e.getMessage()); } return result; } /** * Get ipv4Address on a eth device. * @param vm * @return */ public static String getIpv4Address(VirtualMachine vm) { String[] ipAddressesLocal; String ipv4Address = ""; GuestNicInfo[] guestNicInf = vm.getGuest().getNet(); if (vm != null && guestNicInf != null) { for (GuestNicInfo nicInfo : guestNicInf) { ipAddressesLocal = nicInfo.getIpAddress(); if (ipAddressesLocal != null) { for (String ipAddress : ipAddressesLocal) { if (ipAddress != null && ipAddress.contains(".")) { ipv4Address = ipAddress; break; } } if (ipv4Address != null) { break; } } } } return ipv4Address; } /** * Get an ipv6 address for a vm. * @param vm * @return */ public static String getIpv6Address(VirtualMachine vm) { String[] ipAddressesLocal; String ipv6Address = ""; GuestNicInfo[] guestNicInf = vm.getGuest().getNet(); if (vm != null && guestNicInf != null) { for (GuestNicInfo nicInfo : guestNicInf) { ipAddressesLocal = nicInfo.getIpAddress(); if (ipAddressesLocal != null) { for (String ipAddress : ipAddressesLocal) { if (ipAddress != null && ipAddress.contains(":")) { ipv6Address = ipAddress; break; } } if (ipv6Address != null) { break; } } } } return ipv6Address; } }