package net.juniper.contrail.vcenter;
import com.vmware.vim25.VirtualMachinePowerState;
import com.vmware.vim25.VirtualMachineRuntimeInfo;
import com.vmware.vim25.VirtualMachineConfigInfo;
import com.vmware.vim25.VirtualMachineToolsRunningStatus;
import com.vmware.vim25.mo.HostSystem;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.concurrent.ConcurrentSkipListMap;
import com.vmware.vim25.Event;
import com.vmware.vim25.GuestNicInfo;
import com.vmware.vim25.GuestInfo;
import com.vmware.vim25.ManagedObjectReference;
public class VirtualMachineInfo extends VCenterObject {
private String uuid; // required attribute, key for this object
private String name;
private String displayName;
private String hostName;
private String vrouterIpAddress;
private VirtualMachinePowerState powerState;
private String toolsRunningStatus = VirtualMachineToolsRunningStatus.guestToolsNotRunning.toString();
private SortedMap<String, VirtualMachineInterfaceInfo> vmiInfoMap =
new ConcurrentSkipListMap<String, VirtualMachineInterfaceInfo>();
/* keyed by MAC address, contains only interfaces
* belonging to managed networks
*/
protected static final String contrailVRouterVmNamePrefix = "contrailVM";
// Vmware objects
com.vmware.vim25.mo.VirtualMachine vm;
com.vmware.vim25.mo.HostSystem host;
com.vmware.vim25.mo.VmwareDistributedVirtualSwitch dvs;
String dvsName;
com.vmware.vim25.mo.Datacenter dc;
String dcName;
//API server objects
net.juniper.contrail.api.types.VirtualMachine apiVm;
public VirtualMachineInfo(String uuid) {
if (uuid == null) {
throw new IllegalArgumentException("Cannot init VM with null uuid");
}
this.uuid = uuid;
}
public VirtualMachineInfo(String uuid, String name, String hostName, String vrouterIpAddress,
VirtualMachinePowerState powerState)
{
this.uuid = uuid;
this.name = name;
this.displayName = name;
this.hostName = hostName;
this.vrouterIpAddress = vrouterIpAddress;
this.powerState = powerState;
}
public VirtualMachineInfo(VirtualMachineInfo vmInfo)
{
if (vmInfo == null) {
throw new IllegalArgumentException("Cannot init VM from null VM");
}
this.uuid = vmInfo.uuid;
this.name = vmInfo.name;
this.displayName = vmInfo.displayName;
this.hostName = vmInfo.hostName;
this.vrouterIpAddress = vmInfo.vrouterIpAddress;
this.powerState = vmInfo.powerState;
this.vmiInfoMap = vmInfo.vmiInfoMap;
}
public VirtualMachineInfo(Event event, VCenterDB vcenterDB, VncDB vncDB) throws Exception {
if (event.getDatacenter() != null) {
dcName = event.getDatacenter().getName();
dc = vcenterDB.getVmwareDatacenter(dcName);
}
if (event.getDvs() != null) {
dvsName = event.getDvs().getName();
dvs = vcenterDB.getVmwareDvs(dvsName, dc, dcName);
} else {
dvsName = vcenterDB.contrailDvSwitchName;
dvs = vcenterDB.getVmwareDvs(dvsName, dc, dcName);
}
if (event.getHost() != null) {
hostName = event.getHost().getName();
host = vcenterDB.getVmwareHost(hostName, dc, dcName);
if (event.getVm() != null) {
name = event.getVm().getName();
vm = vcenterDB.getVmwareVirtualMachine(name, host, hostName, dcName);
if (vcenterDB.mode == Mode.VCENTER_AS_COMPUTE
&& !name.toLowerCase().contains(
contrailVRouterVmNamePrefix.toLowerCase())) {
displayName = vm.getConfig().getAnnotation();
} else {
displayName = name;
}
}
}
vrouterIpAddress = vcenterDB.getVRouterVMIpFabricAddress(
hostName, host, contrailVRouterVmNamePrefix);
VirtualMachineConfigInfo config = vm.getConfig();
if (config != null) {
uuid = config.getInstanceUuid();
}
VirtualMachineRuntimeInfo vmRuntimeInfo = vm.getRuntime();
if (vmRuntimeInfo != null) {
powerState = vmRuntimeInfo.getPowerState();
}
GuestInfo guest = vm.getGuest();
if (guest != null) {
toolsRunningStatus = guest.getToolsRunningStatus();
}
setContrailVmActiveState();
vcenterDB.readVirtualMachineInterfaces(this);
if (vcenterDB.mode == Mode.VCENTER_AS_COMPUTE) {
// ipAddress and UUID must be read from Vnc
for (Map.Entry<String, VirtualMachineInterfaceInfo> entry:
vmiInfoMap.entrySet()) {
VirtualMachineInterfaceInfo vmiInfo = entry.getValue();
vncDB.readVirtualMachineInterface(vmiInfo);
}
}
}
private void setContrailVmActiveState() {
if (name.toLowerCase().contains(contrailVRouterVmNamePrefix.toLowerCase())) {
// this is a Contrail VM
if (!powerState.equals(VirtualMachinePowerState.poweredOn)) {
VRouterNotifier.setVrouterActive(vrouterIpAddress, false);
} else if (host != null) {
if (host.getRuntime().isInMaintenanceMode()) {
VRouterNotifier.setVrouterActive(vrouterIpAddress, false);
} else {
VRouterNotifier.setVrouterActive(vrouterIpAddress, true);
}
}
}
}
public VirtualMachineInfo(net.juniper.contrail.api.types.VirtualMachine vm) {
if (vm == null) {
throw new IllegalArgumentException("Cannot init VM with null API VM");
}
vmiInfoMap = new ConcurrentSkipListMap<String, VirtualMachineInterfaceInfo>();
apiVm = vm;
uuid = vm.getUuid();
name = vm.getName();
displayName = vm.getDisplayName();
}
public VirtualMachineInfo(VCenterDB vcenterDB,
com.vmware.vim25.mo.Datacenter dc, String dcName,
com.vmware.vim25.mo.VirtualMachine vm, @SuppressWarnings("rawtypes") Hashtable pTable,
com.vmware.vim25.mo.HostSystem host,
String vrouterIpAddress)
throws Exception {
if (vcenterDB == null || dc == null || dcName == null
|| vm == null || pTable == null) {
throw new IllegalArgumentException("Cannot init VM");
}
this.dc = dc;
this.dcName = dcName;
this.vm = vm;
// Name
uuid = (String) pTable.get("config.instanceUuid");
name = (String) pTable.get("name");
if (vcenterDB.mode == Mode.VCENTER_AS_COMPUTE
&& !name.toLowerCase().contains(
contrailVRouterVmNamePrefix.toLowerCase())) {
displayName = (String) pTable.get("config.annotation");
} else {
displayName = name;
}
if (host == null) {
ManagedObjectReference hostHmor = (ManagedObjectReference) pTable.get("runtime.host");
host = new HostSystem(vm.getServerConnection(), hostHmor);
}
this.host = host;
hostName = host.getName();
powerState = (VirtualMachinePowerState)pTable.get("runtime.powerState");
toolsRunningStatus = (String) pTable.get("guest.toolsRunningStatus");
if (vrouterIpAddress == null) {
vrouterIpAddress = vcenterDB.getVRouterVMIpFabricAddress(
hostName, host, contrailVRouterVmNamePrefix);
}
this.vrouterIpAddress = vrouterIpAddress;
setContrailVmActiveState();
}
public String getHostName() {
return hostName;
}
public void setHostName(String hostName) {
this.hostName = hostName;
}
public String getVrouterIpAddress() {
return vrouterIpAddress;
}
public void setVrouterIpAddress(String vrouterIpAddress) {
this.vrouterIpAddress = vrouterIpAddress;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public VirtualMachinePowerState getPowerState() {
return powerState;
}
public void setPowerState(VirtualMachinePowerState powerState) {
this.powerState = powerState;
}
public boolean isPowerStateEqual(VirtualMachinePowerState powerState) {
if (this.powerState == powerState)
return true;
else
return false;
}
public boolean isPoweredOnState() {
if (powerState == VirtualMachinePowerState.poweredOn)
return true;
else
return false;
}
public String getToolsRunningStatus() {
return toolsRunningStatus;
}
public void setToolsRunningStatus(String toolsRunningStatus) {
this.toolsRunningStatus = toolsRunningStatus;
}
public SortedMap<String, VirtualMachineInterfaceInfo> getVmiInfo() {
return vmiInfoMap;
}
public void setVmiInfo(SortedMap<String, VirtualMachineInterfaceInfo> vmiInfoMap) {
this.vmiInfoMap = vmiInfoMap;
}
public void updatedGuestNics(GuestNicInfo[] nics, VncDB vncDB)
throws Exception {
if (nics == null) {
return;
}
for (GuestNicInfo nic: nics) {
if (nic == null) {
continue;
}
String mac = nic.getMacAddress();
if (vmiInfoMap.containsKey(mac)) {
VirtualMachineInterfaceInfo oldVmi = vmiInfoMap.get(mac);
oldVmi.updatedGuestNic(nic, vncDB);
}
}
}
public void created(VirtualMachineInterfaceInfo vmiInfo) {
vmiInfoMap.put(vmiInfo.getMacAddress(), vmiInfo);
}
public void updated(VirtualMachineInterfaceInfo vmiInfo) {
if (!vmiInfoMap.containsKey(vmiInfo.getMacAddress())) {
vmiInfoMap.put(vmiInfo.getMacAddress(), vmiInfo);
}
}
public void deleted(VirtualMachineInterfaceInfo vmiInfo) {
if (vmiInfoMap.containsKey(vmiInfo.getMacAddress())) {
vmiInfoMap.remove(vmiInfo.getMacAddress());
}
}
public boolean contains(VirtualMachineInterfaceInfo vmiInfo) {
return vmiInfoMap.containsKey(vmiInfo.getMacAddress());
}
public boolean equals(VirtualMachineInfo vm) {
if (vm == null) {
return false;
}
if ((uuid != null && !uuid.equals(vm.uuid))
|| (uuid == null && vm.uuid != null)) {
return false;
}
if ((name != null && !name.equals(vm.name))
|| (name == null && vm.name != null)) {
return false;
}
if ((displayName != null && !displayName.equals(vm.displayName))
|| (displayName == null && vm.displayName != null)) {
return false;
}
if ((vrouterIpAddress != null && !vrouterIpAddress.equals(vm.vrouterIpAddress))
|| (vrouterIpAddress == null && vm.vrouterIpAddress != null)) {
return false;
}
if ((hostName != null && !hostName.equals(vm.hostName))
|| (hostName == null && vm.hostName != null)) {
return false;
}
if ((powerState != null && !powerState.equals(vm.powerState))
|| (powerState == null && vm.powerState != null)) {
return false;
}
return equalVmi(vm);
}
public boolean equalVmi(VirtualMachineInfo vm) {
if (vm == null) {
return false;
}
if (vmiInfoMap.size() != vm.vmiInfoMap.size()) {
return false;
}
Iterator<Entry<String, VirtualMachineInterfaceInfo>> iter1 =
vmiInfoMap.entrySet().iterator();
Iterator<Entry<String, VirtualMachineInterfaceInfo>> iter2 =
vm.vmiInfoMap.entrySet().iterator();
while (iter1.hasNext() && iter2.hasNext()) {
Entry<String, VirtualMachineInterfaceInfo> entry1 = iter1.next();
Entry<String, VirtualMachineInterfaceInfo> entry2 = iter2.next();
if (!entry1.getKey().equals(entry2.getKey())
|| !entry1.getValue().equals(entry2.getValue())) {
return false;
}
}
return true;
}
public String toString() {
return "VM <" + displayName + ", host " + hostName + ", " + uuid + ">";
}
public StringBuffer toStringBuffer() {
StringBuffer s = new StringBuffer(
"VM <" + displayName + ", host " + hostName + ", " + uuid + ">\n\n");
for (Map.Entry<String, VirtualMachineInterfaceInfo> entry:
vmiInfoMap.entrySet()) {
VirtualMachineInterfaceInfo vmiInfo = entry.getValue();
s.append("\t")
.append(vmiInfo).append("\n");
}
s.append("\n");
return s;
}
boolean ignore() {
// by design we skip unconnected VMs
if (vrouterIpAddress == null || vmiInfoMap.size() == 0) {
return true;
}
return false;
}
@Override
void create(VncDB vncDB) throws Exception {
if (ignore()) {
return;
}
vncDB.createVirtualMachine(this);
for (Map.Entry<String, VirtualMachineInterfaceInfo> entry:
vmiInfoMap.entrySet()) {
VirtualMachineInterfaceInfo vmiInfo = entry.getValue();
vmiInfo.create(vncDB);
}
MainDB.created(this);
}
@Override
void update(
VCenterObject obj,
VncDB vncDB) throws Exception {
VirtualMachineInfo newVmInfo = (VirtualMachineInfo)obj;
if (newVmInfo.hostName != null) {
hostName = newVmInfo.hostName;
}
if (newVmInfo.name != null) {
name = newVmInfo.name;
}
if (newVmInfo.displayName != null) {
displayName = newVmInfo.displayName;
}
if (newVmInfo.powerState != null) {
powerState = newVmInfo.powerState;
}
if (newVmInfo.toolsRunningStatus != null) {
toolsRunningStatus = newVmInfo.toolsRunningStatus;
}
if (newVmInfo.vm != null) {
vm = newVmInfo.vm;
}
if (newVmInfo.host != null) {
host = newVmInfo.host;
}
if (newVmInfo.dvs != null) {
dvs = newVmInfo.dvs;
}
if (newVmInfo.dvsName != null) {
dvsName = newVmInfo.dvsName;
}
if (newVmInfo.dc != null) {
dc = newVmInfo.dc;
}
if (newVmInfo.dcName != null) {
dcName = newVmInfo.dcName;
}
if (newVmInfo.apiVm != null) {
apiVm = newVmInfo.apiVm;
}
if (apiVm != null) {
newVmInfo.apiVm = apiVm;
}
if (newVmInfo.vrouterIpAddress != null
&& newVmInfo.vrouterIpAddress.equals(vrouterIpAddress)) {
for (Map.Entry<String, VirtualMachineInterfaceInfo> entry:
newVmInfo.vmiInfoMap.entrySet()) {
VirtualMachineInterfaceInfo vmiInfo = entry.getValue();
vmiInfo.setVmInfo(this);
}
MainDB.update(vmiInfoMap, newVmInfo.vmiInfoMap);
} else {
// VM has been migrated to new host
// delete ports on the old vrouter and create ports on the new vrouter
for (Map.Entry<String, VirtualMachineInterfaceInfo> entry:
vmiInfoMap.entrySet()) {
VirtualMachineInterfaceInfo vmiInfo = entry.getValue();
vmiInfo.deletePort();
}
vrouterIpAddress = newVmInfo.vrouterIpAddress;
for (Map.Entry<String, VirtualMachineInterfaceInfo> entry:
vmiInfoMap.entrySet()) {
VirtualMachineInterfaceInfo vmiInfo = entry.getValue();
vmiInfo.addPort();
}
}
if (vmiInfoMap.size() == 0) {
delete(vncDB);
}
}
@Override
void sync(
VCenterObject obj,
VncDB vncDB) throws Exception {
VirtualMachineInfo oldVmInfo = (VirtualMachineInfo)obj;
if (apiVm == null && oldVmInfo.apiVm != null) {
apiVm = oldVmInfo.apiVm;
}
if (vrouterIpAddress != null && oldVmInfo.vrouterIpAddress == null) {
oldVmInfo.vrouterIpAddress = vrouterIpAddress;
}
// in what cases do we really update the VM
//vncDB.updateVirtualMachine(this);
MainDB.sync(oldVmInfo.vmiInfoMap, this.vmiInfoMap);
if (vmiInfoMap.size() == 0) {
delete(vncDB);
}
}
@Override
void delete(VncDB vncDB)
throws IOException {
VCenterNotify.unwatchVm(this);
for (Map.Entry<String, VirtualMachineInterfaceInfo> entry:
vmiInfoMap.entrySet()) {
VirtualMachineInterfaceInfo vmiInfo = entry.getValue();
vmiInfo.delete(vncDB);
}
vncDB.deleteVirtualMachine(this);
MainDB.deleted(this);
}
public boolean ignore(String vmName) {
// Ignore contrailVRouterVMs since those should not be reflected in
// Contrail VNC
if (name.toLowerCase().contains(
contrailVRouterVmNamePrefix.toLowerCase())) {
return true;
}
return false;
}
}