Skip to content

Commit e094b08

Browse files
authored
vm import, private VLAN integration (#6)
PVLAN support for importing unmanaged VMs and vCenter network discovery
1 parent a0abb31 commit e094b08

File tree

6 files changed

+115
-14
lines changed

6 files changed

+115
-14
lines changed

api/src/main/java/org/apache/cloudstack/api/response/NicResponse.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@ public class NicResponse extends BaseResponse {
118118
@Param(description = "ID of the VLAN/VNI if available", since="4.14.0")
119119
private Integer vlanId;
120120

121+
@SerializedName(ApiConstants.ISOLATED_PVLAN)
122+
@Param(description = "the isolated private VLAN if available", since="4.14.0")
123+
private Integer isolatedPvlanId;
124+
125+
@SerializedName(ApiConstants.ISOLATED_PVLAN_TYPE)
126+
@Param(description = "the isolated private VLAN type if available", since="4.14.0")
127+
private String isolatedPvlanType;
128+
121129
@SerializedName(ApiConstants.ADAPTER_TYPE)
122130
@Param(description = "Type of adapter if available", since="4.14.0")
123131
private String adapterType;
@@ -325,6 +333,22 @@ public void setVlanId(Integer vlanId) {
325333
this.vlanId = vlanId;
326334
}
327335

336+
public Integer getIsolatedPvlanId() {
337+
return isolatedPvlanId;
338+
}
339+
340+
public void setIsolatedPvlanId(Integer isolatedPvlanId) {
341+
this.isolatedPvlanId = isolatedPvlanId;
342+
}
343+
344+
public String getIsolatedPvlanType() {
345+
return isolatedPvlanType;
346+
}
347+
348+
public void setIsolatedPvlanType(String isolatedPvlanType) {
349+
this.isolatedPvlanType = isolatedPvlanType;
350+
}
351+
328352
public String getAdapterType() {
329353
return adapterType;
330354
}

api/src/main/java/org/apache/cloudstack/vm/UnmanagedInstance.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,10 @@ public static class Nic {
270270

271271
private Integer vlan;
272272

273+
private Integer pvlan;
274+
275+
private String pvlanType;
276+
273277
private List<String> ipAddress;
274278

275279
private String pciSlot;
@@ -314,6 +318,22 @@ public void setVlan(Integer vlan) {
314318
this.vlan = vlan;
315319
}
316320

321+
public Integer getPvlan() {
322+
return pvlan;
323+
}
324+
325+
public void setPvlan(Integer pvlan) {
326+
this.pvlan = pvlan;
327+
}
328+
329+
public String getPvlanType() {
330+
return pvlanType;
331+
}
332+
333+
public void setPvlanType(String pvlanType) {
334+
this.pvlanType = pvlanType;
335+
}
336+
317337
public List<String> getIpAddress() {
318338
return ipAddress;
319339
}

plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@
209209
import com.cloud.hypervisor.vmware.mo.DatastoreFile;
210210
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
211211
import com.cloud.hypervisor.vmware.mo.DiskControllerType;
212+
import com.cloud.hypervisor.vmware.mo.DistributedVirtualSwitchMO;
212213
import com.cloud.hypervisor.vmware.mo.FeatureKeyConstants;
213214
import com.cloud.hypervisor.vmware.mo.HostDatastoreSystemMO;
214215
import com.cloud.hypervisor.vmware.mo.HostMO;
@@ -6966,7 +6967,13 @@ private List<UnmanagedInstance.Nic> getUnmanageInstanceNics(VmwareHypervisorHost
69666967
VmwareDistributedVirtualSwitchPvlanSpec pvlanSpec = (VmwareDistributedVirtualSwitchPvlanSpec) settings.getVlan();
69676968
s_logger.trace("Found port " + dvPort.getKey() + " with pvlan " + pvlanSpec.getPvlanId());
69686969
if (pvlanSpec.getPvlanId() > 0 && pvlanSpec.getPvlanId() < 4095) {
6969-
instanceNic.setVlan(pvlanSpec.getPvlanId());
6970+
DistributedVirtualSwitchMO dvSwitchMo = new DistributedVirtualSwitchMO(vmMo.getContext(), dvSwitch);
6971+
Pair<Integer, HypervisorHostHelper.PvlanType> vlanDetails = dvSwitchMo.retrieveVlanFromPvlan(pvlanSpec.getPvlanId(), dvSwitch);
6972+
if (vlanDetails != null && vlanDetails.first() != null && vlanDetails.second() != null) {
6973+
instanceNic.setVlan(vlanDetails.first());
6974+
instanceNic.setPvlan(pvlanSpec.getPvlanId());
6975+
instanceNic.setPvlanType(vlanDetails.second().toString());
6976+
}
69706977
}
69716978
}
69726979
break;

scripts/vm/hypervisor/vmware/discover_networks.py

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -110,23 +110,35 @@ def get_vm_nics(vm, hostPgDict):
110110
dev_backing = dev.backing
111111
portGroup = None
112112
vlanId = None
113+
isolatedPvlan = None
114+
isolatedPvlanType = None
113115
vSwitch = None
114116
if hasattr(dev_backing, 'port'):
115117
portGroupKey = dev.backing.port.portgroupKey
116118
dvsUuid = dev.backing.port.switchUuid
117119
try:
118120
dvs = content.dvSwitchManager.QueryDvsByUuid(dvsUuid)
119121
except:
120-
portGroup = "** Error: DVS not found **"
121-
vlanId = "NA"
122-
vSwitch = "NA"
122+
log_message('\tError: Unable retrieve details for distributed vSwitch ' + dvsUuid)
123+
portGroup = ''
124+
vlanId = ''
125+
vSwitch = ''
123126
else:
124127
pgObj = dvs.LookupDvPortGroup(portGroupKey)
125128
portGroup = pgObj.config.name
126129
try:
127-
vlanId = str(pgObj.config.defaultPortConfig.vlan.vlanId)
130+
if isinstance(pgObj.config.defaultPortConfig.vlan, vim.dvs.VmwareDistributedVirtualSwitch.PvlanSpec):
131+
for pvlanConfig in dvs.config.pvlanConfig:
132+
if pvlanConfig.secondaryVlanId == pgObj.config.defaultPortConfig.vlan.pvlanId:
133+
vlanId = str(pvlanConfig.primaryVlanId)
134+
isolatedPvlanType = pvlanConfig.pvlanType
135+
isolatedPvlan = str(pgObj.config.defaultPortConfig.vlan.pvlanId)
136+
break
137+
else:
138+
vlanId = str(pgObj.config.defaultPortConfig.vlan.vlanId)
128139
except AttributeError:
129-
vlanId = '0'
140+
log_message('\tError: Unable retrieve details for portgroup ' + portGroup)
141+
vlanId = ''
130142
vSwitch = str(dvs.name)
131143
else:
132144
portGroup = dev.backing.network.name
@@ -138,11 +150,9 @@ def get_vm_nics(vm, hostPgDict):
138150
vlanId = str(p.spec.vlanId)
139151
vSwitch = str(p.spec.vswitchName)
140152
if portGroup is None:
141-
portGroup = 'NA'
153+
portGroup = ''
142154
if vlanId is None:
143-
vlanId = 'NA'
144-
if vSwitch is None:
145-
vSwitch = 'NA'
155+
vlanId = ''
146156
vmHostName = None
147157
vmClusterName = None
148158
try:
@@ -153,14 +163,14 @@ def get_vm_nics(vm, hostPgDict):
153163
vmClusterName = vm.runtime.host.parent.name
154164
except AttributeError:
155165
vmClusterName = ''
156-
add_network(portGroup, vlanId, vSwitch, vm.name, dev.deviceInfo.label, dev.macAddress, vmClusterName, vmHostName)
166+
add_network(portGroup, vlanId, isolatedPvlanType, isolatedPvlan, vSwitch, vm.name, dev.deviceInfo.label, dev.macAddress, vmClusterName, vmHostName)
157167
log_message('\t\t' + dev.deviceInfo.label + '->' + dev.macAddress +
158168
' @ ' + vSwitch + '->' + portGroup +
159169
' (VLAN ' + vlanId + ')')
160170
except AttributeError:
161171
log_message('\tError: Unable retrieve details for ' + vm.name)
162172

163-
def add_network(portGroup, vlanId, vSwitch, vmName, vmDeviceLabel, vmMacAddress, vmClusterName, vmHostName):
173+
def add_network(portGroup, vlanId, isolatedPvlanType, isolatedPvlan, vSwitch, vmName, vmDeviceLabel, vmMacAddress, vmClusterName, vmHostName):
164174
key = vSwitch + '->' + portGroup + ' (VLAN ' + vlanId + ')'
165175
device = {"label": vmDeviceLabel, "macaddress": vmMacAddress}
166176
vm = {"name":vmName, "device": device}
@@ -179,7 +189,13 @@ def add_network(portGroup, vlanId, vSwitch, vmName, vmDeviceLabel, vmMacAddress,
179189
except KeyError:
180190
cluster = vmClusterName
181191

182-
network = {"portgroup": portGroup, "cluster": cluster, "host": host, "vlanid": vlanId, "switch": vSwitch, "virtualmachines": vms}
192+
network = {"portgroup": portGroup, "cluster": cluster, "host": host, "switch": vSwitch, "virtualmachines": vms}
193+
if vlanId != '':
194+
network["vlanid"] = vlanId
195+
if isolatedPvlan is not None:
196+
network["isolatedpvlan"] = isolatedPvlan
197+
if isolatedPvlanType is not None:
198+
network["isolatedpvlantype"] = isolatedPvlanType
183199
networksDict[key] = network
184200

185201

server/src/main/java/org/apache/cloudstack/vm/VmImportManagerImpl.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,8 @@ private UnmanagedInstanceResponse createUnmanagedInstanceResponse(UnmanagedInsta
267267
nicResponse.setIpAddresses(nic.getIpAddress());
268268
}
269269
nicResponse.setVlanId(nic.getVlan());
270+
nicResponse.setIsolatedPvlanId(nic.getPvlan());
271+
nicResponse.setIsolatedPvlanType(nic.getPvlanType());
270272
response.addNic(nicResponse);
271273
}
272274
}
@@ -556,9 +558,16 @@ private void checkUnmanagedNicAndNetworkForImport(UnmanagedInstance.Nic nic, Net
556558
if (!autoAssign && network.getGuestType().equals(Network.GuestType.Isolated)) {
557559
return;
558560
}
559-
if (nic.getVlan() != null && nic.getVlan() != 0 && (Strings.isNullOrEmpty(network.getBroadcastUri().toString()) || !network.getBroadcastUri().toString().equals(String.format("vlan://%d", nic.getVlan())))) {
561+
if (nic.getVlan() != null && nic.getVlan() != 0 && nic.getPvlan() == null &&
562+
(Strings.isNullOrEmpty(network.getBroadcastUri().toString()) ||
563+
!network.getBroadcastUri().toString().equals(String.format("vlan://%d", nic.getVlan())))) {
560564
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VLAN of network(ID: %s) %s is found different from the VLAN of nic(ID: %s) vlan://%d during VM import", network.getUuid(), network.getBroadcastUri().toString(), nic.getNicId(), nic.getVlan()));
561565
}
566+
if (nic.getVlan() != null && nic.getVlan() != 0 && nic.getPvlan() != null && nic.getPvlan() != 0 &&
567+
(Strings.isNullOrEmpty(network.getBroadcastUri().toString()) ||
568+
!network.getBroadcastUri().toString().equals(String.format("pvlan://%d-i%d", nic.getVlan(), nic.getPvlan())))) {
569+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("PVLAN of network(ID: %s) %s is found different from the VLAN of nic(ID: %s) pvlan://%d-i%d during VM import", network.getUuid(), network.getBroadcastUri().toString(), nic.getNicId(), nic.getVlan(), nic.getPvlan()));
570+
}
562571
}
563572

564573
private void checkUnmanagedNicAndNetworkHostnameForImport(UnmanagedInstance.Nic nic, Network network, final String hostName) throws ServerApiException {

vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
import org.apache.log4j.Logger;
2626

27+
import com.cloud.utils.Pair;
2728
import com.vmware.vim25.DVPortgroupConfigSpec;
2829
import com.vmware.vim25.DVSConfigInfo;
2930
import com.vmware.vim25.ManagedObjectReference;
@@ -169,4 +170,28 @@ public Map<Integer, HypervisorHostHelper.PvlanType> retrieveVlanPvlan(int vlanid
169170
return result;
170171
}
171172

173+
public Pair<Integer, HypervisorHostHelper.PvlanType> retrieveVlanFromPvlan(int pvlanid, ManagedObjectReference dvSwitchMor) throws Exception {
174+
assert (dvSwitchMor != null);
175+
176+
Pair<Integer, HypervisorHostHelper.PvlanType> result = null;
177+
178+
VMwareDVSConfigInfo configinfo = (VMwareDVSConfigInfo)_context.getVimClient().getDynamicProperty(dvSwitchMor, "config");
179+
List<VMwareDVSPvlanMapEntry> pvlanConfig = null;
180+
pvlanConfig = configinfo.getPvlanConfig();
181+
182+
if (null == pvlanConfig || 0 == pvlanConfig.size()) {
183+
return result;
184+
}
185+
186+
// Iterate through the pvlanMapList and check if the specified pvlan id exist. If it does, set the fields in result accordingly.
187+
for (VMwareDVSPvlanMapEntry mapEntry : pvlanConfig) {
188+
int entryVlanid = mapEntry.getPrimaryVlanId();
189+
int entryPvlanid = mapEntry.getSecondaryVlanId();
190+
if (pvlanid == entryPvlanid) {
191+
result = new Pair<>(entryVlanid, HypervisorHostHelper.PvlanType.valueOf(mapEntry.getPvlanType()));
192+
break;
193+
}
194+
}
195+
return result;
196+
}
172197
}

0 commit comments

Comments
 (0)