// Copyright 2012 Citrix Systems, Inc. Licensed under the
// Apache License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License. Citrix Systems, Inc.
// reserves all rights not expressly granted by 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.
//
// Automatically generated by addcopyright.py at 04/03/2012
package com.cloud.hypervisor.vmware.mo;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import com.cloud.hypervisor.vmware.util.VmwareContext;
import com.cloud.hypervisor.vmware.util.VmwareHelper;
import com.cloud.utils.ActionDelegate;
import com.cloud.utils.Pair;
import com.cloud.utils.cisco.n1kv.vsm.NetconfHelper;
import com.cloud.utils.cisco.n1kv.vsm.PolicyMap;
import com.cloud.utils.cisco.n1kv.vsm.PortProfile;
import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.BindingType;
import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.OperationType;
import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.PortProfileType;
import com.cloud.utils.cisco.n1kv.vsm.VsmCommand.SwitchPortMode;
import com.cloud.utils.db.GlobalLock;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.net.NetUtils;
import com.vmware.vim25.BoolPolicy;
import com.vmware.vim25.DVPortgroupConfigInfo;
import com.vmware.vim25.DVSTrafficShapingPolicy;
import com.vmware.vim25.DynamicProperty;
import com.vmware.vim25.HostNetworkTrafficShapingPolicy;
import com.vmware.vim25.HostPortGroupSpec;
import com.vmware.vim25.HostVirtualSwitch;
import com.vmware.vim25.HttpNfcLeaseDeviceUrl;
import com.vmware.vim25.HttpNfcLeaseInfo;
import com.vmware.vim25.HttpNfcLeaseState;
import com.vmware.vim25.LongPolicy;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.ObjectContent;
import com.vmware.vim25.OvfCreateImportSpecParams;
import com.vmware.vim25.OvfCreateImportSpecResult;
import com.vmware.vim25.OvfFileItem;
import com.vmware.vim25.VirtualDeviceConfigSpec;
import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
import com.vmware.vim25.VirtualLsiLogicController;
import com.vmware.vim25.VirtualMachineConfigSpec;
import com.vmware.vim25.VirtualMachineFileInfo;
import com.vmware.vim25.VirtualMachineVideoCard;
import com.vmware.vim25.VirtualSCSISharing;
public class HypervisorHostHelper {
private static final Logger s_logger = Logger.getLogger(HypervisorHostHelper.class);
private static final int DEFAULT_LOCK_TIMEOUT_SECONDS = 600;
private static final String s_policyNamePrefix = "cloud.policy.";
// make vmware-base loosely coupled with cloud-specific stuff, duplicate VLAN.UNTAGGED constant here
private static final String UNTAGGED_VLAN_NAME = "untagged";
public static VirtualMachineMO findVmFromObjectContent(VmwareContext context,
ObjectContent[] ocs, String name) {
if(ocs != null && ocs.length > 0) {
for(ObjectContent oc : ocs) {
DynamicProperty prop = oc.getPropSet(0);
assert(prop != null);
if(prop.getVal().toString().equals(name))
return new VirtualMachineMO(context, oc.getObj());
}
}
return null;
}
public static ManagedObjectReference findDatastoreWithBackwardsCompatibility(VmwareHypervisorHost hyperHost, String uuidName) throws Exception {
ManagedObjectReference morDs = hyperHost.findDatastore(uuidName.replace("-", ""));
if(morDs == null)
morDs = hyperHost.findDatastore(uuidName);
return morDs;
}
public static DatastoreMO getHyperHostDatastoreMO(VmwareHypervisorHost hyperHost, String datastoreName) throws Exception {
ObjectContent[] ocs = hyperHost.getDatastorePropertiesOnHyperHost(new String[] { "name"} );
if(ocs != null && ocs.length > 0) {
for(ObjectContent oc : ocs) {
DynamicProperty[] objProps = oc.getPropSet();
if(objProps != null) {
for(DynamicProperty objProp : objProps) {
if(objProp.getVal().toString().equals(datastoreName))
return new DatastoreMO(hyperHost.getContext(), oc.getObj());
}
}
}
}
return null;
}
public static String getPublicNetworkNamePrefix(String vlanId) {
if (UNTAGGED_VLAN_NAME.equalsIgnoreCase(vlanId)) {
return "cloud.public.untagged";
} else {
return "cloud.public." + vlanId;
}
}
public static String composeCloudNetworkName(String prefix, String vlanId, Integer networkRateMbps, String vSwitchName) {
StringBuffer sb = new StringBuffer(prefix);
if(vlanId == null || UNTAGGED_VLAN_NAME.equalsIgnoreCase(vlanId))
sb.append(".untagged");
else
sb.append(".").append(vlanId);
if(networkRateMbps != null && networkRateMbps.intValue() > 0)
sb.append(".").append(String.valueOf(networkRateMbps));
else
sb.append(".0");
sb.append(".").append(VersioningContants.PORTGROUP_NAMING_VERSION);
sb.append("-").append(vSwitchName);
return sb.toString();
}
public static Map<String, String> getValidatedVsmCredentials(VmwareContext context) throws Exception {
Map<String, String> vsmCredentials = context.getStockObject("vsmcredentials");
String msg;
if (vsmCredentials == null || vsmCredentials.size() != 3) {
msg = "Failed to retrieve required credentials of Nexus VSM from database.";
s_logger.error(msg);
throw new Exception(msg);
}
String vsmIp = vsmCredentials.containsKey("vsmip") ? vsmCredentials.get("vsmip") : null;
String vsmUserName = vsmCredentials.containsKey("vsmusername") ? vsmCredentials.get("vsmusername") : null;
String vsmPassword = vsmCredentials.containsKey("vsmpassword") ? vsmCredentials.get("vsmpassword") : null;
if (vsmIp == null || vsmIp.isEmpty() || vsmUserName == null || vsmUserName.isEmpty() || vsmPassword == null
|| vsmPassword.isEmpty()) {
msg = "Detected invalid credentials for Nexus 1000v.";
s_logger.error(msg);
throw new Exception(msg);
}
return vsmCredentials;
}
public static void createPortProfile(VmwareContext context, String ethPortProfileName, String networkName,
Integer vlanId, Integer networkRateMbps, long peakBandwidth, long burstSize) throws Exception {
Map<String, String> vsmCredentials = getValidatedVsmCredentials(context);
String vsmIp = vsmCredentials.get("vsmip");
String vsmUserName = vsmCredentials.get("vsmusername");
String vsmPassword = vsmCredentials.get("vsmpassword");
String msg;
NetconfHelper netconfClient;
try {
s_logger.info("Connecting to Nexus 1000v: " + vsmIp);
netconfClient = new NetconfHelper(vsmIp, vsmUserName, vsmPassword);
s_logger.info("Successfully connected to Nexus 1000v : " + vsmIp);
} catch (CloudRuntimeException e) {
msg = "Failed to connect to Nexus 1000v " + vsmIp + " with credentials of user " + vsmUserName
+ ". Exception: " + e.toString();
s_logger.error(msg);
throw new CloudRuntimeException(msg);
}
String policyName = s_policyNamePrefix;
int averageBandwidth = 0;
if (networkRateMbps != null) {
averageBandwidth = networkRateMbps.intValue();
policyName += averageBandwidth;
}
try {
// TODO(sateesh): Change the type of peakBandwidth & burstRate in
// PolicyMap to long.
if (averageBandwidth > 0) {
s_logger.debug("Adding policy map " + policyName);
netconfClient.addPolicyMap(policyName, averageBandwidth, (int) peakBandwidth, (int) burstSize);
}
} catch (CloudRuntimeException e) {
msg = "Failed to add policy map of " + policyName + " with parameters " + "committed rate = "
+ averageBandwidth + "peak bandwidth = " + peakBandwidth + "burst size = " + burstSize
+ ". Exception: " + e.toString();
s_logger.error(msg);
if (netconfClient != null) {
netconfClient.disconnect();
s_logger.debug("Disconnected Nexus 1000v session.");
}
throw new CloudRuntimeException(msg);
}
List<Pair<OperationType, String>> params = new ArrayList<Pair<OperationType, String>>();
if (vlanId != null) {
// No need to update ethernet port profile for untagged vlans
params.add(new Pair<OperationType, String>(OperationType.addvlanid, vlanId.toString()));
try {
s_logger.info("Updating Ethernet port profile " + ethPortProfileName + " with VLAN " + vlanId);
netconfClient.updatePortProfile(ethPortProfileName, SwitchPortMode.trunk, params);
s_logger.info("Added " + vlanId + " to Ethernet port profile " + ethPortProfileName);
} catch (CloudRuntimeException e) {
msg = "Failed to update Ethernet port profile " + ethPortProfileName + " with VLAN " + vlanId
+ ". Exception: " + e.toString();
s_logger.error(msg);
if(netconfClient != null) {
netconfClient.disconnect();
s_logger.debug("Disconnected Nexus 1000v session.");
}
throw new CloudRuntimeException(msg);
}
}
try {
if (vlanId == null) {
s_logger.info("Adding port profile configured over untagged VLAN.");
netconfClient.addPortProfile(networkName, PortProfileType.vethernet, BindingType.portbindingstatic, SwitchPortMode.access, 0);
} else {
s_logger.info("Adding port profile configured over VLAN : " + vlanId.toString());
netconfClient.addPortProfile(networkName, PortProfileType.vethernet, BindingType.portbindingstatic, SwitchPortMode.access, vlanId.intValue());
}
} catch (CloudRuntimeException e) {
msg = "Failed to add vEthernet port profile " + networkName + "." + ". Exception: " + e.toString();
s_logger.error(msg);
if(netconfClient != null) {
netconfClient.disconnect();
s_logger.debug("Disconnected Nexus 1000v session.");
}
throw new CloudRuntimeException(msg);
}
try {
if (averageBandwidth > 0) {
s_logger.info("Associating policy map " + policyName + " with port profile " + networkName + ".");
netconfClient.attachServicePolicy(policyName, networkName);
}
}
catch(CloudRuntimeException e) {
msg = "Failed to associate policy map " + policyName + " with port profile " + networkName
+ ". Exception: " + e.toString();
s_logger.error(msg);
throw new CloudRuntimeException(msg);
} finally {
if (netconfClient != null) {
netconfClient.disconnect();
s_logger.debug("Disconnected Nexus 1000v session.");
}
}
}
public static void updatePortProfile(VmwareContext context, String ethPortProfileName, String vethPortProfileName,
Integer vlanId, Integer networkRateMbps, long peakBandwidth, long burstRate) throws Exception {
NetconfHelper netconfClient = null;
Map<String, String> vsmCredentials = getValidatedVsmCredentials(context);
String vsmIp = vsmCredentials.get("vsmip");
String vsmUserName = vsmCredentials.get("vsmusername");
String vsmPassword = vsmCredentials.get("vsmpassword");
String msg;
try {
netconfClient = new NetconfHelper(vsmIp, vsmUserName, vsmPassword);
} catch (CloudRuntimeException e) {
msg = "Failed to connect to Nexus 1000v " + vsmIp + " with credentials of user " + vsmUserName
+ ". Exception: " + e.toString();
s_logger.error(msg);
throw new CloudRuntimeException(msg);
}
PortProfile portProfile = netconfClient.getPortProfileByName(vethPortProfileName);
int averageBandwidth = 0;
String policyName = s_policyNamePrefix;
if (networkRateMbps != null) {
averageBandwidth = networkRateMbps.intValue();
policyName += averageBandwidth;
}
if (averageBandwidth > 0) {
PolicyMap policyMap = netconfClient.getPolicyMapByName(portProfile.inputPolicyMap);
if (policyMap.committedRate == averageBandwidth && policyMap.peakRate == peakBandwidth
&& policyMap.burstRate == burstRate) {
s_logger.debug("Detected that policy map is already applied to port profile " + vethPortProfileName);
if (netconfClient != null) {
netconfClient.disconnect();
s_logger.debug("Disconnected Nexus 1000v session.");
}
return;
} else {
try {
// TODO(sateesh): Change the type of peakBandwidth &
// burstRate in PolicyMap to long.
s_logger.info("Adding policy map " + policyName);
netconfClient.addPolicyMap(policyName, averageBandwidth, (int) peakBandwidth, (int) burstRate);
} catch (CloudRuntimeException e) {
msg = "Failed to add policy map of " + policyName + " with parameters " + "committed rate = "
+ averageBandwidth + "peak bandwidth = " + peakBandwidth + "burst size = " + burstRate
+ ". Exception: " + e.toString();
s_logger.error(msg);
if (netconfClient != null) {
netconfClient.disconnect();
s_logger.debug("Disconnected Nexus 1000v session.");
}
throw new CloudRuntimeException(msg);
}
try {
s_logger.info("Associating policy map " + policyName + " with port profile " + vethPortProfileName
+ ".");
netconfClient.attachServicePolicy(policyName, vethPortProfileName);
} catch (CloudRuntimeException e) {
msg = "Failed to associate policy map " + policyName + " with port profile " + vethPortProfileName
+ ". Exception: " + e.toString();
s_logger.error(msg);
if (netconfClient != null) {
netconfClient.disconnect();
s_logger.debug("Disconnected Nexus 1000v session.");
}
throw new CloudRuntimeException(msg);
}
}
}
if (vlanId == null) {
s_logger.info("Skipping update operation over ethernet port profile " + ethPortProfileName
+ " for untagged VLAN.");
if (netconfClient != null) {
netconfClient.disconnect();
s_logger.debug("Disconnected Nexus 1000v session.");
}
return;
}
String currentVlan = portProfile.vlan;
String newVlan = Integer.toString(vlanId.intValue());
if (currentVlan.equalsIgnoreCase(newVlan)) {
if (netconfClient != null) {
netconfClient.disconnect();
s_logger.debug("Disconnected Nexus 1000v session.");
}
return;
}
List<Pair<OperationType, String>> params = new ArrayList<Pair<OperationType, String>>();
params.add(new Pair<OperationType, String>(OperationType.addvlanid, newVlan));
try {
s_logger.info("Updating vEthernet port profile with VLAN " + vlanId.toString());
netconfClient.updatePortProfile(ethPortProfileName, SwitchPortMode.trunk, params);
} catch (CloudRuntimeException e) {
msg = "Failed to update ethernet port profile " + ethPortProfileName + " with parameters "
+ params.toString() + ". Exception: " + e.toString();
s_logger.error(msg);
if (netconfClient != null) {
netconfClient.disconnect();
s_logger.debug("Disconnected Nexus 1000v session.");
}
throw new CloudRuntimeException(msg);
}
try {
netconfClient.updatePortProfile(vethPortProfileName, SwitchPortMode.access, params);
} catch (CloudRuntimeException e) {
msg = "Failed to update vEthernet port profile " + vethPortProfileName + " with parameters "
+ params.toString() + ". Exception: " + e.toString();
s_logger.error(msg);
if (netconfClient != null) {
netconfClient.disconnect();
s_logger.debug("Disconnected Nexus 1000v session.");
}
throw new CloudRuntimeException(msg);
}
}
/**
* @param ethPortProfileName
* @param namePrefix
* @param hostMo
* @param vlanId
* @param networkRateMbps
* @param networkRateMulticastMbps
* @param timeOutMs
* @return
* @throws Exception
*/
public static Pair<ManagedObjectReference, String> prepareNetwork(String ethPortProfileName, String namePrefix,
HostMO hostMo, String vlanId, Integer networkRateMbps, Integer networkRateMulticastMbps, long timeOutMs)
throws Exception {
ManagedObjectReference morNetwork = null;
VmwareContext context = hostMo.getContext();
ManagedObjectReference dcMor = hostMo.getHyperHostDatacenter();
DatacenterMO dataCenterMo = new DatacenterMO(context, dcMor);
ManagedObjectReference morEthernetPortProfile = dataCenterMo.getDvPortGroupMor(ethPortProfileName);
if (morEthernetPortProfile == null) {
String msg = "Unable to find Ethernet port profile " + ethPortProfileName;
s_logger.error(msg);
throw new Exception(msg);
}
else {
s_logger.info("Found Ethernet port profile " + ethPortProfileName);
}
boolean createGCTag = false;
String networkName;
Integer vid = null;
if(vlanId != null && !UNTAGGED_VLAN_NAME.equalsIgnoreCase(vlanId)) {
createGCTag = true;
vid = Integer.parseInt(vlanId);
}
networkName = composeCloudNetworkName(namePrefix, vlanId, networkRateMbps, ethPortProfileName);
// TODO(sateesh): Enable this for VMware DVS.
// DVSTrafficShapingPolicy shapingPolicy = null;
// if (networkRateMbps != null && networkRateMbps.intValue() > 0) {
// shapingPolicy = new DVSTrafficShapingPolicy();
// BoolPolicy isEnabled = new BoolPolicy();
// LongPolicy averageBandwidth = new LongPolicy();
// LongPolicy peakBandwidth = new LongPolicy();
// LongPolicy burstSize = new LongPolicy();
//
// isEnabled.setValue(true);
// averageBandwidth.setValue((long) networkRateMbps.intValue() * 1024L * 1024L);
// // We chose 50% higher allocation than average bandwidth.
// // TODO(sateesh): Also let user specify the peak coefficient
// peakBandwidth.setValue((long) (averageBandwidth.getValue() * 1.5));
// // TODO(sateesh): Also let user specify the burst coefficient
// burstSize.setValue((long) (5 * averageBandwidth.getValue() / 8));
//
// shapingPolicy.setEnabled(isEnabled);
// shapingPolicy.setAverageBandwidth(averageBandwidth);
// shapingPolicy.setPeakBandwidth(peakBandwidth);
// shapingPolicy.setBurstSize(burstSize);
// }
DVPortgroupConfigInfo spec = dataCenterMo.getDvPortGroupSpec(networkName);
long averageBandwidth = 0L;
if (networkRateMbps != null && networkRateMbps.intValue() > 0) {
averageBandwidth = (long) (networkRateMbps.intValue() * 1024L * 1024L);
}
// We chose 50% higher allocation than average bandwidth.
// TODO(sateesh): Also let user specify the peak coefficient
long peakBandwidth = (long) (averageBandwidth * 1.5);
// TODO(sateesh): Also let user specify the burst coefficient
long burstSize = 5 * averageBandwidth / 8;
boolean bWaitPortGroupReady = false;
if (!dataCenterMo.hasDvPortGroup(networkName)) {
s_logger.info("Port profile " + networkName + " not found.");
createPortProfile(context, ethPortProfileName, networkName, vid, networkRateMbps, peakBandwidth, burstSize);
bWaitPortGroupReady = true;
} else {
s_logger.info("Port profile " + networkName + " found.");
bWaitPortGroupReady = true;
updatePortProfile(context, ethPortProfileName, networkName, vid, networkRateMbps, peakBandwidth, burstSize);
}
// Wait for dvPortGroup on vCenter
if(bWaitPortGroupReady)
morNetwork = waitForDvPortGroupReady(dataCenterMo, networkName, timeOutMs);
else
morNetwork = dataCenterMo.getDvPortGroupMor(networkName);
if (morNetwork == null) {
String msg = "Failed to create guest network " + networkName;
s_logger.error(msg);
throw new Exception(msg);
}
if(createGCTag) {
NetworkMO networkMo = new NetworkMO(hostMo.getContext(), morNetwork);
networkMo.setCustomFieldValue(CustomFieldConstants.CLOUD_GC_DVP, "true");
s_logger.debug("Added custom field : " + CustomFieldConstants.CLOUD_GC_DVP);
}
return new Pair<ManagedObjectReference, String>(morNetwork, networkName);
}
private static ManagedObjectReference waitForDvPortGroupReady(
DatacenterMO dataCenterMo, String dvPortGroupName, long timeOutMs) throws Exception {
ManagedObjectReference morDvPortGroup = null;
// if DvPortGroup is just created, we may fail to retrieve it, we
// need to retry
long startTick = System.currentTimeMillis();
while (System.currentTimeMillis() - startTick <= timeOutMs) {
morDvPortGroup = dataCenterMo.getDvPortGroupMor(dvPortGroupName);
if (morDvPortGroup != null) {
break;
}
s_logger.info("Waiting for dvPortGroup " + dvPortGroupName + " to be ready");
Thread.sleep(1000);
}
return morDvPortGroup;
}
// This method would be used for VMware Distributed Virtual Switch.
private static boolean isSpecMatch(DVPortgroupConfigInfo spec, Integer vid, DVSTrafficShapingPolicy shapingPolicy) {
DVSTrafficShapingPolicy currentTrafficShapingPolicy;
currentTrafficShapingPolicy = spec.getDefaultPortConfig().getInShapingPolicy();
// TODO(sateesh): Extract and compare vendor specific configuration specification as well.
// DistributedVirtualSwitchKeyedOpaqueBlob[] vendorSpecificConfig = spec.getVendorSpecificConfig();
assert(currentTrafficShapingPolicy != null);
LongPolicy averageBandwidth = currentTrafficShapingPolicy.getAverageBandwidth();
LongPolicy burstSize = currentTrafficShapingPolicy.getBurstSize();
LongPolicy peakBandwidth = currentTrafficShapingPolicy.getPeakBandwidth();
BoolPolicy isEnabled = currentTrafficShapingPolicy.getEnabled();
if(!isEnabled.getValue())
return false;
if(averageBandwidth != null && !averageBandwidth.equals(shapingPolicy.getAverageBandwidth())) {
if(s_logger.isInfoEnabled()) {
s_logger.info("Average bandwidth setting in shaping policy doesn't match with existing setting.");
}
return false;
} else if(burstSize != null && !burstSize.equals(shapingPolicy.getBurstSize())) {
if(s_logger.isInfoEnabled()) {
s_logger.info("Burst size setting in shaping policy doesn't match with existing setting.");
}
return false;
} else if(peakBandwidth != null && !peakBandwidth.equals(shapingPolicy.getPeakBandwidth())) {
if(s_logger.isInfoEnabled()) {
s_logger.info("Peak bandwidth setting in shaping policy doesn't match with existing setting.");
}
return false;
}
return true;
}
public static Pair<ManagedObjectReference, String> prepareNetwork(String vSwitchName, String namePrefix,
HostMO hostMo, String vlanId, Integer networkRateMbps, Integer networkRateMulticastMbps,
long timeOutMs, boolean syncPeerHosts) throws Exception {
HostVirtualSwitch vSwitch;
vSwitch = hostMo.getHostVirtualSwitchByName(vSwitchName);
if (vSwitch == null) {
String msg = "Unable to find vSwitch" + vSwitchName;
s_logger.error(msg);
throw new Exception(msg);
}
boolean createGCTag = false;
String networkName;
Integer vid = null;
if(vlanId != null && !UNTAGGED_VLAN_NAME.equalsIgnoreCase(vlanId)) {
createGCTag = true;
vid = Integer.parseInt(vlanId);
}
networkName = composeCloudNetworkName(namePrefix, vlanId, networkRateMbps, vSwitchName);
HostNetworkTrafficShapingPolicy shapingPolicy = null;
if(networkRateMbps != null && networkRateMbps.intValue() > 0) {
shapingPolicy = new HostNetworkTrafficShapingPolicy();
shapingPolicy.setEnabled(true);
shapingPolicy.setAverageBandwidth((long)networkRateMbps.intValue()*1024L*1024L);
//
// TODO : people may have different opinion on how to set the following
//
// give 50% premium to peek
shapingPolicy.setPeakBandwidth((long)(shapingPolicy.getAverageBandwidth()*1.5));
// allow 5 seconds of burst transfer
shapingPolicy.setBurstSize(5*shapingPolicy.getAverageBandwidth()/8);
}
boolean bWaitPortGroupReady = false;
if (!hostMo.hasPortGroup(vSwitch, networkName)) {
hostMo.createPortGroup(vSwitch, networkName, vid, shapingPolicy);
bWaitPortGroupReady = true;
} else {
HostPortGroupSpec spec = hostMo.getPortGroupSpec(networkName);
if(!isSpecMatch(spec, vid, shapingPolicy)) {
hostMo.updatePortGroup(vSwitch, networkName, vid, shapingPolicy);
bWaitPortGroupReady = true;
}
}
ManagedObjectReference morNetwork;
if(bWaitPortGroupReady)
morNetwork = waitForNetworkReady(hostMo, networkName, timeOutMs);
else
morNetwork = hostMo.getNetworkMor(networkName);
if (morNetwork == null) {
String msg = "Failed to create guest network " + networkName;
s_logger.error(msg);
throw new Exception(msg);
}
if(createGCTag) {
NetworkMO networkMo = new NetworkMO(hostMo.getContext(), morNetwork);
networkMo.setCustomFieldValue(CustomFieldConstants.CLOUD_GC, "true");
}
if(syncPeerHosts) {
ManagedObjectReference morParent = hostMo.getParentMor();
if(morParent != null && morParent.getType().equals("ClusterComputeResource")) {
// to be conservative, lock cluster
GlobalLock lock = GlobalLock.getInternLock("ClusterLock." + morParent.get_value());
try {
if(lock.lock(DEFAULT_LOCK_TIMEOUT_SECONDS)) {
try {
ManagedObjectReference[] hosts = (ManagedObjectReference[])hostMo.getContext().getServiceUtil().getDynamicProperty(morParent, "host");
if(hosts != null) {
for(ManagedObjectReference otherHost: hosts) {
if(!otherHost.get_value().equals(hostMo.getMor().get_value())) {
HostMO otherHostMo = new HostMO(hostMo.getContext(), otherHost);
try {
if(s_logger.isDebugEnabled())
s_logger.debug("Prepare network on other host, vlan: " + vlanId + ", host: " + otherHostMo.getHostName());
prepareNetwork(vSwitchName, namePrefix, otherHostMo, vlanId, networkRateMbps, networkRateMulticastMbps, timeOutMs, false);
} catch(Exception e) {
s_logger.warn("Unable to prepare network on other host, vlan: " + vlanId + ", host: " + otherHostMo.getHostName());
}
}
}
}
} finally {
lock.unlock();
}
} else {
s_logger.warn("Unable to lock cluster to prepare guest network, vlan: " + vlanId);
}
} finally {
lock.releaseRef();
}
}
}
s_logger.info("Network " + networkName + " is ready on vSwitch " + vSwitchName);
return new Pair<ManagedObjectReference, String>(morNetwork, networkName);
}
private static boolean isSpecMatch(HostPortGroupSpec spec, Integer vlanId, HostNetworkTrafficShapingPolicy shapingPolicy) {
// check VLAN configuration
if(vlanId != null) {
if(vlanId.intValue() != spec.getVlanId())
return false;
} else {
if(spec.getVlanId() != 0)
return false;
}
// check traffic shaping configuration
HostNetworkTrafficShapingPolicy policyInSpec = null;
if(spec.getPolicy() != null)
policyInSpec = spec.getPolicy().getShapingPolicy();
if(policyInSpec != null && shapingPolicy == null || policyInSpec == null && shapingPolicy != null)
return false;
if(policyInSpec == null && shapingPolicy == null)
return true;
// so far policyInSpec and shapingPolicy should both not be null
if(policyInSpec.getEnabled() == null || !policyInSpec.getEnabled().booleanValue())
return false;
if(policyInSpec.getAverageBandwidth() == null || policyInSpec.getAverageBandwidth().longValue() != shapingPolicy.getAverageBandwidth().longValue())
return false;
if(policyInSpec.getPeakBandwidth() == null || policyInSpec.getPeakBandwidth().longValue() != shapingPolicy.getPeakBandwidth().longValue())
return false;
if(policyInSpec.getBurstSize() == null || policyInSpec.getBurstSize().longValue() != shapingPolicy.getBurstSize().longValue())
return false;
return true;
}
public static ManagedObjectReference waitForNetworkReady(HostMO hostMo,
String networkName, long timeOutMs) throws Exception {
ManagedObjectReference morNetwork = null;
// if portGroup is just created, getNetwork may fail to retrieve it, we
// need to retry
long startTick = System.currentTimeMillis();
while (System.currentTimeMillis() - startTick <= timeOutMs) {
morNetwork = hostMo.getNetworkMor(networkName);
if (morNetwork != null) {
break;
}
s_logger.info("Waiting for network " + networkName + " to be ready");
Thread.sleep(1000);
}
return morNetwork;
}
public static boolean createBlankVm(VmwareHypervisorHost host, String vmName,
int cpuCount, int cpuSpeedMHz, int cpuReservedMHz, boolean limitCpuUse, int memoryMB, int memoryReserveMB, String guestOsIdentifier,
ManagedObjectReference morDs, boolean snapshotDirToParent) throws Exception {
if(s_logger.isInfoEnabled())
s_logger.info("Create blank VM. cpuCount: " + cpuCount + ", cpuSpeed(MHz): " + cpuSpeedMHz + ", mem(Mb): " + memoryMB);
// VM config basics
VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec();
vmConfig.setName(vmName);
VmwareHelper.setBasicVmConfig(vmConfig, cpuCount, cpuSpeedMHz, cpuReservedMHz, memoryMB, memoryReserveMB, guestOsIdentifier, limitCpuUse);
// Scsi controller
VirtualLsiLogicController scsiController = new VirtualLsiLogicController();
scsiController.setSharedBus(VirtualSCSISharing.noSharing);
scsiController.setBusNumber(0);
scsiController.setKey(1);
VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec();
scsiControllerSpec.setDevice(scsiController);
scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.add);
VirtualMachineFileInfo fileInfo = new VirtualMachineFileInfo();
DatastoreMO dsMo = new DatastoreMO(host.getContext(), morDs);
fileInfo.setVmPathName(String.format("[%s]", dsMo.getName()));
vmConfig.setFiles(fileInfo);
VirtualMachineVideoCard videoCard = new VirtualMachineVideoCard();
videoCard.setControllerKey(100);
videoCard.setUseAutoDetect(true);
VirtualDeviceConfigSpec videoDeviceSpec = new VirtualDeviceConfigSpec();
videoDeviceSpec.setDevice(videoCard);
videoDeviceSpec.setOperation(VirtualDeviceConfigSpecOperation.add);
vmConfig.setDeviceChange(new VirtualDeviceConfigSpec[] { scsiControllerSpec, videoDeviceSpec });
if(host.createVm(vmConfig)) {
VirtualMachineMO vmMo = host.findVmOnHyperHost(vmName);
assert(vmMo != null);
int ideControllerKey = -1;
while(ideControllerKey < 0) {
ideControllerKey = vmMo.tryGetIDEDeviceControllerKey();
if(ideControllerKey >= 0)
break;
s_logger.info("Waiting for IDE controller be ready in VM: " + vmName);
Thread.sleep(1000);
}
if(snapshotDirToParent) {
String snapshotDir = String.format("/vmfs/volumes/%s/", dsMo.getName());
s_logger.info("Switch snapshot working directory to " + snapshotDir + " for " + vmName);
vmMo.setSnapshotDirectory(snapshotDir);
// Don't have a good way to test if the VM is really ready for use through normal API after configuration file manipulation,
// delay 3 seconds
Thread.sleep(3000);
}
s_logger.info("Blank VM: " + vmName + " is ready for use");
return true;
}
return false;
}
public static String resolveHostNameInUrl(DatacenterMO dcMo, String url) {
s_logger.info("Resolving host name in url through vCenter, url: " + url);
URI uri;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
s_logger.warn("URISyntaxException on url " + url);
return url;
}
String host = uri.getHost();
if(NetUtils.isValidIp(host)) {
s_logger.info("host name in url is already in IP address, url: " + url);
return url;
}
try {
ManagedObjectReference morHost = dcMo.findHost(host);
if(morHost != null) {
HostMO hostMo = new HostMO(dcMo.getContext(), morHost);
String managementPortGroupName;
if(hostMo.getHostType() == VmwareHostType.ESXi)
managementPortGroupName = (String)dcMo.getContext().getStockObject("manageportgroup");
else
managementPortGroupName = (String)dcMo.getContext().getStockObject("serviceconsole");
VmwareHypervisorHostNetworkSummary summary = hostMo.getHyperHostNetworkSummary(managementPortGroupName);
if(summary == null) {
s_logger.warn("Unable to resolve host name in url through vSphere, url: " + url);
return url;
}
String hostIp = summary.getHostIp();
try {
URI resolvedUri = new URI(uri.getScheme(), uri.getUserInfo(), hostIp, uri.getPort(), uri.getPath(), uri.getQuery(), uri.getFragment());
s_logger.info("url " + url + " is resolved to " + resolvedUri.toString() + " through vCenter");
return resolvedUri.toString();
} catch (URISyntaxException e) {
assert(false);
return url;
}
}
} catch(Exception e) {
s_logger.warn("Unexpected exception ", e);
}
return url;
}
public static void importVmFromOVF(VmwareHypervisorHost host, String ovfFilePath, String vmName, DatastoreMO dsMo, String diskOption,
ManagedObjectReference morRp, ManagedObjectReference morHost) throws Exception {
assert(morRp != null);
OvfCreateImportSpecParams importSpecParams = new OvfCreateImportSpecParams();
importSpecParams.setHostSystem(morHost);
importSpecParams.setLocale("US");
importSpecParams.setEntityName(vmName);
importSpecParams.setDeploymentOption("");
importSpecParams.setDiskProvisioning(diskOption); // diskOption: thin, thick, etc
importSpecParams.setPropertyMapping(null);
String ovfDescriptor = HttpNfcLeaseMO.readOvfContent(ovfFilePath);
VmwareContext context = host.getContext();
OvfCreateImportSpecResult ovfImportResult = context.getService().createImportSpec(
context.getServiceContent().getOvfManager(), ovfDescriptor, morRp,
dsMo.getMor(), importSpecParams);
if(ovfImportResult == null) {
String msg = "createImportSpec() failed. ovfFilePath: " + ovfFilePath + ", vmName: "
+ vmName + ", diskOption: " + diskOption;
s_logger.error(msg);
throw new Exception(msg);
}
DatacenterMO dcMo = new DatacenterMO(context, host.getHyperHostDatacenter());
ManagedObjectReference morLease = context.getService().importVApp(morRp,
ovfImportResult.getImportSpec(), dcMo.getVmFolder(), morHost);
if(morLease == null) {
String msg = "importVApp() failed. ovfFilePath: " + ovfFilePath + ", vmName: "
+ vmName + ", diskOption: " + diskOption;
s_logger.error(msg);
throw new Exception(msg);
}
final HttpNfcLeaseMO leaseMo = new HttpNfcLeaseMO(context, morLease);
HttpNfcLeaseState state = leaseMo.waitState(
new HttpNfcLeaseState[] { HttpNfcLeaseState.ready, HttpNfcLeaseState.error });
try {
if(state == HttpNfcLeaseState.ready) {
final long totalBytes = HttpNfcLeaseMO.calcTotalBytes(ovfImportResult);
File ovfFile = new File(ovfFilePath);
HttpNfcLeaseInfo httpNfcLeaseInfo = leaseMo.getLeaseInfo();
HttpNfcLeaseDeviceUrl[] deviceUrls = httpNfcLeaseInfo.getDeviceUrl();
long bytesAlreadyWritten = 0;
final HttpNfcLeaseMO.ProgressReporter progressReporter = leaseMo.createProgressReporter();
try {
for (HttpNfcLeaseDeviceUrl deviceUrl : deviceUrls) {
String deviceKey = deviceUrl.getImportKey();
for (OvfFileItem ovfFileItem : ovfImportResult.getFileItem()) {
if (deviceKey.equals(ovfFileItem.getDeviceId())) {
String absoluteFile = ovfFile.getParent() + File.separator + ovfFileItem.getPath();
String urlToPost = deviceUrl.getUrl();
urlToPost = resolveHostNameInUrl(dcMo, urlToPost);
context.uploadVmdkFile(ovfFileItem.isCreate() ? "PUT" : "POST", urlToPost, absoluteFile,
bytesAlreadyWritten, new ActionDelegate<Long> () {
public void action(Long param) {
progressReporter.reportProgress((int)(param * 100 / totalBytes));
}
});
bytesAlreadyWritten += ovfFileItem.getSize();
}
}
}
} finally {
progressReporter.close();
}
leaseMo.updateLeaseProgress(100);
}
} finally {
leaseMo.completeLease();
}
}
}