Skip to content

Commit 4c65259

Browse files
[CLOUDSTACK-10226] CloudStack is not importing Local storage properly
CloudStack is importing as Local storage any XenServer SR that is of type LVM or EXT. This causes a problem when one wants to use both Direct attach storage and local storage. Moreover, CloudStack was not importing all of the local storage that a host has available when local storage is enabled. It was only importing the First SR it sees. To fix the first problem we started ignoring SRs that have the flag shared=true when discovering local storages. SRs configured to be shared are used as direct attached storage, and therefore should not be imported again as local ones. To fix the second problem, we started loading all Local storage and importing them accordingly to ACS.
1 parent 82bcc74 commit 4c65259

14 files changed

Lines changed: 421 additions & 157 deletions

File tree

plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java

Lines changed: 132 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@
5151

5252
import org.apache.cloudstack.storage.to.TemplateObjectTO;
5353
import org.apache.cloudstack.storage.to.VolumeObjectTO;
54+
import org.apache.commons.collections.CollectionUtils;
5455
import org.apache.commons.collections.MapUtils;
5556
import org.apache.commons.io.FileUtils;
57+
import org.apache.commons.lang3.BooleanUtils;
5658
import org.apache.log4j.Logger;
5759
import org.apache.xmlrpc.XmlRpcException;
5860
import org.joda.time.Duration;
@@ -173,7 +175,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
173175
* used to describe what type of resource a storage device is of
174176
*/
175177
public enum SRType {
176-
EXT, FILE, ISCSI, ISO, LVM, LVMOHBA, LVMOISCSI,
178+
EXT, ISO, LVM, LVMOHBA, LVMOISCSI,
177179
/**
178180
* used for resigning metadata (like SR UUID and VDI UUID when a
179181
* particular storage manager is installed on a XenServer host (for back-end snapshots to work))
@@ -756,11 +758,6 @@ public HashMap<String, String> clusterVMMetaDataSync(final Connection conn) {
756758
final HashMap<String, String> vmMetaDatum = new HashMap<String, String>();
757759
try {
758760
final Map<VM, VM.Record> vm_map = VM.getAllRecords(conn); // USE
759-
// THIS TO
760-
// GET ALL
761-
// VMS
762-
// FROM A
763-
// CLUSTER
764761
if (vm_map != null) {
765762
for (final VM.Record record : vm_map.values()) {
766763
if (record.isControlDomain || record.isASnapshot || record.isATemplate) {
@@ -2645,76 +2642,6 @@ public String getLabel() {
26452642
return result;
26462643
}
26472644

2648-
protected SR getLocalEXTSR(final Connection conn) {
2649-
try {
2650-
final Map<SR, SR.Record> map = SR.getAllRecords(conn);
2651-
if (map != null && !map.isEmpty()) {
2652-
for (final Map.Entry<SR, SR.Record> entry : map.entrySet()) {
2653-
final SR.Record srRec = entry.getValue();
2654-
if (SRType.FILE.equals(srRec.type) || SRType.EXT.equals(srRec.type)) {
2655-
final Set<PBD> pbds = srRec.PBDs;
2656-
if (pbds == null) {
2657-
continue;
2658-
}
2659-
for (final PBD pbd : pbds) {
2660-
final Host host = pbd.getHost(conn);
2661-
if (!isRefNull(host) && host.getUuid(conn).equals(_host.getUuid())) {
2662-
if (!pbd.getCurrentlyAttached(conn)) {
2663-
pbd.plug(conn);
2664-
}
2665-
final SR sr = entry.getKey();
2666-
sr.scan(conn);
2667-
return sr;
2668-
}
2669-
}
2670-
}
2671-
}
2672-
}
2673-
} catch (final XenAPIException e) {
2674-
final String msg = "Unable to get local EXTSR in host:" + _host.getUuid() + e.toString();
2675-
s_logger.warn(msg);
2676-
} catch (final XmlRpcException e) {
2677-
final String msg = "Unable to get local EXTSR in host:" + _host.getUuid() + e.getCause();
2678-
s_logger.warn(msg);
2679-
}
2680-
return null;
2681-
}
2682-
2683-
protected SR getLocalLVMSR(final Connection conn) {
2684-
try {
2685-
final Map<SR, SR.Record> map = SR.getAllRecords(conn);
2686-
if (map != null && !map.isEmpty()) {
2687-
for (final Map.Entry<SR, SR.Record> entry : map.entrySet()) {
2688-
final SR.Record srRec = entry.getValue();
2689-
if (SRType.LVM.equals(srRec.type)) {
2690-
final Set<PBD> pbds = srRec.PBDs;
2691-
if (pbds == null) {
2692-
continue;
2693-
}
2694-
for (final PBD pbd : pbds) {
2695-
final Host host = pbd.getHost(conn);
2696-
if (!isRefNull(host) && host.getUuid(conn).equals(_host.getUuid())) {
2697-
if (!pbd.getCurrentlyAttached(conn)) {
2698-
pbd.plug(conn);
2699-
}
2700-
final SR sr = entry.getKey();
2701-
sr.scan(conn);
2702-
return sr;
2703-
}
2704-
}
2705-
}
2706-
}
2707-
}
2708-
} catch (final XenAPIException e) {
2709-
final String msg = "Unable to get local LVMSR in host:" + _host.getUuid() + e.toString();
2710-
s_logger.warn(msg);
2711-
} catch (final XmlRpcException e) {
2712-
final String msg = "Unable to get local LVMSR in host:" + _host.getUuid() + e.getCause();
2713-
s_logger.warn(msg);
2714-
}
2715-
return null;
2716-
}
2717-
27182645
public String getLowestAvailableVIFDeviceNum(final Connection conn, final VM vm) {
27192646
String vmName = "";
27202647
try {
@@ -3670,75 +3597,144 @@ public StartupCommand[] initialize() throws IllegalArgumentException {
36703597
} catch (final Throwable e) {
36713598
s_logger.warn("Check for master failed, failing the FULL Cluster sync command");
36723599
}
3673-
final StartupStorageCommand sscmd = initializeLocalSR(conn);
3674-
if (sscmd != null) {
3675-
return new StartupCommand[] {cmd, sscmd};
3600+
List<StartupStorageCommand> startUpLocalStorageCommands = null;
3601+
try {
3602+
startUpLocalStorageCommands = initializeLocalSrs(conn);
3603+
} catch (XenAPIException | XmlRpcException e) {
3604+
s_logger.warn("Could not initialize local SRs on host: " + _host.getUuid(), e);
3605+
}
3606+
if (CollectionUtils.isEmpty(startUpLocalStorageCommands)) {
3607+
return new StartupCommand[] {cmd};
36763608
}
3677-
return new StartupCommand[] {cmd};
3609+
return createStartupCommandsArray(cmd, startUpLocalStorageCommands);
36783610
}
36793611

3680-
protected StartupStorageCommand initializeLocalSR(final Connection conn) {
3681-
final SR lvmsr = getLocalLVMSR(conn);
3682-
if (lvmsr != null) {
3683-
try {
3684-
_host.setLocalSRuuid(lvmsr.getUuid(conn));
3685-
3686-
final String lvmuuid = lvmsr.getUuid(conn);
3687-
final long cap = lvmsr.getPhysicalSize(conn);
3688-
if (cap > 0) {
3689-
final long avail = cap - lvmsr.getPhysicalUtilisation(conn);
3690-
lvmsr.setNameLabel(conn, lvmuuid);
3691-
final String name = "Cloud Stack Local LVM Storage Pool for " + _host.getUuid();
3692-
lvmsr.setNameDescription(conn, name);
3693-
final Host host = Host.getByUuid(conn, _host.getUuid());
3694-
final String address = host.getAddress(conn);
3695-
final StoragePoolInfo pInfo = new StoragePoolInfo(lvmuuid, address, SRType.LVM.toString(), SRType.LVM.toString(), StoragePoolType.LVM, cap, avail);
3696-
final StartupStorageCommand cmd = new StartupStorageCommand();
3697-
cmd.setPoolInfo(pInfo);
3698-
cmd.setGuid(_host.getUuid());
3699-
cmd.setDataCenter(Long.toString(_dcId));
3700-
cmd.setResourceType(Storage.StorageResourceType.STORAGE_POOL);
3701-
return cmd;
3612+
/**
3613+
* We simply create an array and add the {@link StartupRoutingCommand} as the first element of the array. Then, we add all elements from startUpLocalStorageCommands
3614+
*/
3615+
private StartupCommand[] createStartupCommandsArray(StartupRoutingCommand startupRoutingCommand, List<StartupStorageCommand> startUpLocalStorageCommands) {
3616+
StartupCommand[] startupCommands = new StartupCommand[startUpLocalStorageCommands.size() + 1];
3617+
startupCommands[0] = startupRoutingCommand;
3618+
for (int i = 1; i < startupCommands.length; i++) {
3619+
startupCommands[i] = startUpLocalStorageCommands.get(i - 1);
3620+
}
3621+
return startupCommands;
3622+
}
3623+
3624+
/**
3625+
* This method will return a list of all local SRs.
3626+
* An SR is considered local if it meets all of the following criteria:
3627+
* <ul>
3628+
* <li> {@link Record#shared} is equal to false
3629+
* <li> The PBDs of the SR ({@link Record#PBDs}) are connected to host {@link #_host}
3630+
* <li> SR type is equal to the {@link SRType} sent as parameter
3631+
* </ul>
3632+
*/
3633+
protected List<SR> getAllLocalSrForType(Connection conn, SRType srType) throws XenAPIException, XmlRpcException {
3634+
List<SR> localSrs = new ArrayList<>();
3635+
Map<SR, SR.Record> allSrRecords = SR.getAllRecords(conn);
3636+
if (MapUtils.isEmpty(allSrRecords)) {
3637+
return localSrs;
3638+
}
3639+
for (Map.Entry<SR, SR.Record> entry : allSrRecords.entrySet()) {
3640+
SR.Record srRec = entry.getValue();
3641+
if (!srType.equals(srRec.type)) {
3642+
continue;
3643+
}
3644+
if (BooleanUtils.toBoolean(srRec.shared)) {
3645+
continue;
3646+
}
3647+
Set<PBD> pbds = srRec.PBDs;
3648+
if (CollectionUtils.isEmpty(pbds)) {
3649+
continue;
3650+
}
3651+
for (PBD pbd : pbds) {
3652+
Host host = pbd.getHost(conn);
3653+
if (!isRefNull(host) && org.apache.commons.lang3.StringUtils.equals(host.getUuid(conn), _host.getUuid())) {
3654+
if (!pbd.getCurrentlyAttached(conn)) {
3655+
s_logger.debug(String.format("PBD [%s] of local SR [%s] was unplugged, pluggin it now", pbd.getUuid(conn), srRec.uuid));
3656+
pbd.plug(conn);
3657+
}
3658+
s_logger.debug("Scanning local SR: " + srRec.uuid);
3659+
SR sr = entry.getKey();
3660+
sr.scan(conn);
3661+
localSrs.add(sr);
37023662
}
3703-
} catch (final XenAPIException e) {
3704-
final String msg = "build local LVM info err in host:" + _host.getUuid() + e.toString();
3705-
s_logger.warn(msg);
3706-
} catch (final XmlRpcException e) {
3707-
final String msg = "build local LVM info err in host:" + _host.getUuid() + e.getMessage();
3708-
s_logger.warn(msg);
37093663
}
37103664
}
3665+
s_logger.debug(String.format("Found %d local storage of type [%s] for host [%s]", localSrs.size(), srType.toString(), _host.getUuid()));
3666+
return localSrs;
3667+
}
37113668

3712-
final SR extsr = getLocalEXTSR(conn);
3713-
if (extsr != null) {
3714-
try {
3715-
final String extuuid = extsr.getUuid(conn);
3716-
_host.setLocalSRuuid(extuuid);
3717-
final long cap = extsr.getPhysicalSize(conn);
3718-
if (cap > 0) {
3719-
final long avail = cap - extsr.getPhysicalUtilisation(conn);
3720-
extsr.setNameLabel(conn, extuuid);
3721-
final String name = "Cloud Stack Local EXT Storage Pool for " + _host.getUuid();
3722-
extsr.setNameDescription(conn, name);
3723-
final Host host = Host.getByUuid(conn, _host.getUuid());
3724-
final String address = host.getAddress(conn);
3725-
final StoragePoolInfo pInfo = new StoragePoolInfo(extuuid, address, SRType.EXT.toString(), SRType.EXT.toString(), StoragePoolType.EXT, cap, avail);
3726-
final StartupStorageCommand cmd = new StartupStorageCommand();
3727-
cmd.setPoolInfo(pInfo);
3728-
cmd.setGuid(_host.getUuid());
3729-
cmd.setDataCenter(Long.toString(_dcId));
3730-
cmd.setResourceType(Storage.StorageResourceType.STORAGE_POOL);
3731-
return cmd;
3732-
}
3733-
} catch (final XenAPIException e) {
3734-
final String msg = "build local EXT info err in host:" + _host.getUuid() + e.toString();
3735-
s_logger.warn(msg);
3736-
} catch (final XmlRpcException e) {
3737-
final String msg = "build local EXT info err in host:" + _host.getUuid() + e.getMessage();
3738-
s_logger.warn(msg);
3669+
/**
3670+
* This method will prepare Local SRs to be used by Apache CloudStack.
3671+
*/
3672+
protected List<StartupStorageCommand> initializeLocalSrs(Connection conn) throws XenAPIException, XmlRpcException {
3673+
List<StartupStorageCommand> localStorageStartupCommands = new ArrayList<>();
3674+
List<SR> allLocalSrs = getAllLocalSrs(conn);
3675+
3676+
for (SR sr : allLocalSrs) {
3677+
long totalCapacity = sr.getPhysicalSize(conn);
3678+
if (totalCapacity > 0) {
3679+
StartupStorageCommand cmd = createStartUpStorageCommand(conn, sr);
3680+
localStorageStartupCommands.add(cmd);
37393681
}
37403682
}
3741-
return null;
3683+
return localStorageStartupCommands;
3684+
}
3685+
3686+
/**
3687+
* This method will retrieve all Local SRs according to {@link #getAllLocalSrForType(Connection, SRType)}.
3688+
* The types used are {@link SRType#LVM} and {@link SRType#EXT}.
3689+
*
3690+
*/
3691+
protected List<SR> getAllLocalSrs(Connection conn) throws XenAPIException, XmlRpcException {
3692+
List<SR> allLocalSrLvmType = getAllLocalSrForType(conn, SRType.LVM);
3693+
List<SR> allLocalSrExtType = getAllLocalSrForType(conn, SRType.EXT);
3694+
List<SR> allLocalSrs = new ArrayList<>(allLocalSrLvmType);
3695+
allLocalSrs.addAll(allLocalSrExtType);
3696+
return allLocalSrs;
3697+
}
3698+
3699+
/**
3700+
* This method creates the StartUp storage command for the local SR.
3701+
* We will configure 'name-label' and 'description' using {@link #configureStorageNameAndDescription(Connection, SR)}.
3702+
* Then, we will create the POJO {@link StoragePoolInfo} with SR's information using method {@link #createStoragePoolInfo(Connection, SR)}.
3703+
*/
3704+
protected StartupStorageCommand createStartUpStorageCommand(Connection conn, SR sr) throws XenAPIException, XmlRpcException {
3705+
configureStorageNameAndDescription(conn, sr);
3706+
3707+
StoragePoolInfo storagePoolInfo = createStoragePoolInfo(conn, sr);
3708+
3709+
StartupStorageCommand cmd = new StartupStorageCommand();
3710+
cmd.setPoolInfo(storagePoolInfo);
3711+
cmd.setGuid(_host.getUuid());
3712+
cmd.setDataCenter(Long.toString(_dcId));
3713+
cmd.setResourceType(Storage.StorageResourceType.STORAGE_POOL);
3714+
3715+
String.format("StartUp command created for local storage [%s] of type [%s] on host [%s]", storagePoolInfo.getUuid(), storagePoolInfo.getPoolType(), _host.getUuid());
3716+
return cmd;
3717+
}
3718+
3719+
/**
3720+
* Instantiate {@link StoragePoolInfo} with SR's information.
3721+
*/
3722+
protected StoragePoolInfo createStoragePoolInfo(Connection conn, SR sr) throws XenAPIException, XmlRpcException {
3723+
long totalCapacity = sr.getPhysicalSize(conn);
3724+
String srUuid = sr.getUuid(conn);
3725+
Host host = Host.getByUuid(conn, _host.getUuid());
3726+
String address = host.getAddress(conn);
3727+
long availableCapacity = totalCapacity - sr.getPhysicalUtilisation(conn);
3728+
String srType = sr.getType(conn).toUpperCase();
3729+
return new StoragePoolInfo(srUuid, address, srType, srType, StoragePoolType.valueOf(srType), totalCapacity, availableCapacity);
3730+
}
3731+
3732+
protected void configureStorageNameAndDescription(Connection conn, SR sr) throws XenAPIException, XmlRpcException {
3733+
String srUuid = sr.getUuid(conn);
3734+
sr.setNameLabel(conn, srUuid);
3735+
3736+
String nameFormat = "Cloud Stack Local (%s) Storage Pool for %s";
3737+
sr.setNameDescription(conn, String.format(nameFormat, sr.getType(conn), _host.getUuid()));
37423738
}
37433739

37443740
public boolean isDeviceUsed(final Connection conn, final VM vm, final Long deviceId) {

plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/XenServer56Resource.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ public Boolean checkHeartbeat(final String hostuuid) {
125125
@Override
126126
public StartupCommand[] initialize() {
127127
pingXAPI();
128-
final StartupCommand[] cmds = super.initialize();
129-
return cmds;
128+
return super.initialize();
130129
}
131130
}

plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/XsHost.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ public class XsHost {
4343
private Integer cpuSockets;
4444
private int cpus;
4545
private String productVersion;
46-
private String localSRuuid;
4746

4847
public String getSystemvmisouuid() {
4948
return systemvmisouuid;
@@ -197,14 +196,6 @@ public void setProductVersion(final String productVersion) {
197196
this.productVersion = productVersion;
198197
}
199198

200-
public String getLocalSRuuid() {
201-
return localSRuuid;
202-
}
203-
204-
public void setLocalSRuuid(final String localSRuuid) {
205-
this.localSRuuid = localSRuuid;
206-
}
207-
208199
@Override
209200
public String toString() {
210201
return new StringBuilder("XS[").append(uuid).append("-").append(ip).append("]").toString();

0 commit comments

Comments
 (0)