Skip to content

Commit 4eac1a1

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 fa7c1e2 commit 4eac1a1

8 files changed

Lines changed: 676 additions & 440 deletions

File tree

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

Lines changed: 379 additions & 410 deletions
Large diffs are not rendered by default.

plugins/hypervisors/xenserver/src/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/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();

plugins/hypervisors/xenserver/test/com/cloud/hypervisor/xenserver/resource/CitrixResourceBaseTest.java

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,41 @@
1616
package com.cloud.hypervisor.xenserver.resource;
1717

1818
import java.io.File;
19+
import java.util.ArrayList;
20+
import java.util.HashMap;
21+
import java.util.HashSet;
1922
import java.util.List;
23+
import java.util.Map;
24+
import java.util.Set;
2025

26+
import org.apache.xmlrpc.XmlRpcException;
2127
import org.junit.Assert;
2228
import org.junit.Test;
29+
import org.junit.runner.RunWith;
30+
import org.mockito.BDDMockito;
31+
import org.mockito.InOrder;
2332
import org.mockito.Mockito;
33+
import org.mockito.Spy;
2434
import org.powermock.api.mockito.PowerMockito;
35+
import org.powermock.core.classloader.annotations.PrepareForTest;
36+
import org.powermock.modules.junit4.PowerMockRunner;
2537

38+
import com.cloud.agent.api.StartupStorageCommand;
39+
import com.cloud.agent.api.StoragePoolInfo;
40+
import com.cloud.hypervisor.xenserver.resource.CitrixResourceBase.SRType;
41+
import com.cloud.storage.Storage.StoragePoolType;
42+
import com.cloud.storage.Storage.StorageResourceType;
2643
import com.cloud.utils.script.Script;
44+
import com.xensource.xenapi.Connection;
45+
import com.xensource.xenapi.Host;
46+
import com.xensource.xenapi.PBD;
47+
import com.xensource.xenapi.SR;
48+
import com.xensource.xenapi.Types.XenAPIException;
2749

50+
@RunWith(PowerMockRunner.class)
2851
public class CitrixResourceBaseTest {
2952

53+
@Spy
3054
protected CitrixResourceBase citrixResourceBase = new CitrixResourceBase() {
3155
@Override
3256
protected String getPatchFilePath() {
@@ -92,4 +116,193 @@ public void testGetGuestOsTypeOther() {
92116
String guestOsType = citrixResourceBase.getGuestOsType(platformEmulator);
93117
Assert.assertEquals(platformEmulator, guestOsType);
94118
}
119+
120+
@Test
121+
@PrepareForTest(SR.class)
122+
public void getAllLocalSrForTypeTest() throws Exception {
123+
String mockHostUuid = "hostUuid";
124+
citrixResourceBase._host.setUuid(mockHostUuid);
125+
126+
Connection connectionMock = Mockito.mock(Connection.class);
127+
128+
SR srExtShared = Mockito.mock(SR.class);
129+
SR srExtNonShared = Mockito.mock(SR.class);
130+
131+
List<SR> expectedListOfSrs = new ArrayList<>();
132+
expectedListOfSrs.add(srExtNonShared);
133+
134+
Set<PBD> pbds = new HashSet<>();
135+
PBD pbdMock = Mockito.mock(PBD.class);
136+
Host hostMock = Mockito.mock(Host.class);
137+
Mockito.when(hostMock.getUuid(connectionMock)).thenReturn(mockHostUuid);
138+
Mockito.when(hostMock.toWireString()).thenReturn(mockHostUuid);
139+
140+
Mockito.when(pbdMock.getHost(connectionMock)).thenReturn(hostMock);
141+
pbds.add(pbdMock);
142+
143+
SR.Record srExtSharedRecord = Mockito.mock(SR.Record.class);
144+
srExtSharedRecord.type = "EXT";
145+
srExtSharedRecord.shared = true;
146+
srExtSharedRecord.PBDs = pbds;
147+
148+
SR.Record srExtNonSharedRecord = Mockito.mock(SR.Record.class);
149+
srExtNonSharedRecord.type = "EXT";
150+
srExtNonSharedRecord.shared = false;
151+
srExtNonSharedRecord.PBDs = pbds;
152+
153+
Map<SR, SR.Record> mapOfSrsRecords = new HashMap<>();
154+
mapOfSrsRecords.put(srExtShared, srExtSharedRecord);
155+
mapOfSrsRecords.put(srExtNonShared, srExtNonSharedRecord);
156+
157+
PowerMockito.mockStatic(SR.class);
158+
BDDMockito.given(SR.getAllRecords(connectionMock)).willReturn(mapOfSrsRecords);
159+
160+
List<SR> allLocalSrForType = citrixResourceBase.getAllLocalSrForType(connectionMock, SRType.EXT);
161+
162+
Assert.assertEquals(expectedListOfSrs.size(), allLocalSrForType.size());
163+
Assert.assertEquals(expectedListOfSrs.get(0), allLocalSrForType.get(0));
164+
}
165+
166+
@Test
167+
public void getAllLocalSrForTypeNoSrsFoundTest() throws XenAPIException, XmlRpcException {
168+
Connection connectionMock = Mockito.mock(Connection.class);
169+
List<SR> allLocalSrForType = citrixResourceBase.getAllLocalSrForType(connectionMock, SRType.EXT);
170+
Assert.assertTrue(allLocalSrForType.isEmpty());
171+
}
172+
173+
@Test
174+
public void getAllLocalSrsTest() throws XenAPIException, XmlRpcException {
175+
Connection connectionMock = Mockito.mock(Connection.class);
176+
SR sr1 = Mockito.mock(SR.class);
177+
List<SR> srsExt = new ArrayList<>();
178+
srsExt.add(sr1);
179+
180+
SR sr2 = Mockito.mock(SR.class);
181+
List<SR> srsLvm = new ArrayList<>();
182+
srsLvm.add(sr2);
183+
184+
Mockito.doReturn(srsExt).when(citrixResourceBase).getAllLocalSrForType(connectionMock, SRType.EXT);
185+
Mockito.doReturn(srsLvm).when(citrixResourceBase).getAllLocalSrForType(connectionMock, SRType.LVM);
186+
187+
List<SR> allLocalSrs = citrixResourceBase.getAllLocalSrs(connectionMock);
188+
189+
Assert.assertEquals(srsExt.size() + srsLvm.size(), allLocalSrs.size());
190+
Assert.assertEquals(srsExt.get(0), allLocalSrs.get(1));
191+
Assert.assertEquals(srsLvm.get(0), allLocalSrs.get(0));
192+
193+
InOrder inOrder = Mockito.inOrder(citrixResourceBase);
194+
inOrder.verify(citrixResourceBase).getAllLocalSrForType(connectionMock, SRType.LVM);
195+
inOrder.verify(citrixResourceBase).getAllLocalSrForType(connectionMock, SRType.EXT);
196+
}
197+
198+
@Test
199+
@PrepareForTest(Host.class)
200+
public void createStoragePoolInfoTest() throws XenAPIException, XmlRpcException {
201+
Connection connectionMock = Mockito.mock(Connection.class);
202+
Host hostMock = Mockito.mock(Host.class);
203+
SR srMock = Mockito.mock(SR.class);
204+
205+
String hostAddress = "hostAddress";
206+
Mockito.when(hostMock.getAddress(connectionMock)).thenReturn(hostAddress);
207+
208+
String hostUuid = "hostUuid";
209+
citrixResourceBase._host.setUuid(hostUuid);
210+
211+
PowerMockito.mockStatic(Host.class);
212+
PowerMockito.when(Host.getByUuid(connectionMock, hostUuid)).thenReturn(hostMock);
213+
214+
String srType = "ext";
215+
String srUuid = "srUuid";
216+
long srPhysicalSize = 100l;
217+
long physicalUtilization = 10l;
218+
219+
Mockito.when(srMock.getPhysicalSize(connectionMock)).thenReturn(srPhysicalSize);
220+
Mockito.when(srMock.getUuid(connectionMock)).thenReturn(srUuid);
221+
Mockito.when(srMock.getPhysicalUtilisation(connectionMock)).thenReturn(physicalUtilization);
222+
Mockito.when(srMock.getType(connectionMock)).thenReturn(srType);
223+
224+
StoragePoolInfo storagePoolInfo = citrixResourceBase.createStoragePoolInfo(connectionMock, srMock);
225+
226+
Assert.assertEquals(srUuid, storagePoolInfo.getUuid());
227+
Assert.assertEquals(hostAddress, storagePoolInfo.getHost());
228+
Assert.assertEquals(srType.toUpperCase(), storagePoolInfo.getHostPath());
229+
Assert.assertEquals(srType.toUpperCase(), storagePoolInfo.getLocalPath());
230+
Assert.assertEquals(StoragePoolType.EXT, storagePoolInfo.getPoolType());
231+
Assert.assertEquals(srPhysicalSize, storagePoolInfo.getCapacityBytes());
232+
Assert.assertEquals(srPhysicalSize - physicalUtilization, storagePoolInfo.getAvailableBytes());
233+
}
234+
235+
@Test
236+
public void configureStorageNameAndDescriptionTest() throws XenAPIException, XmlRpcException {
237+
String nameFormat = "Cloud Stack Local (%s) Storage Pool for %s";
238+
239+
String hostUuid = "hostUuid";
240+
citrixResourceBase._host.setUuid(hostUuid);
241+
242+
Connection connectionMock = Mockito.mock(Connection.class);
243+
SR srMock = Mockito.mock(SR.class);
244+
245+
String srUuid = "srUuid";
246+
String srType = "ext";
247+
String expectedNameDescription = String.format(nameFormat, srType, hostUuid);
248+
249+
Mockito.when(srMock.getUuid(connectionMock)).thenReturn(srUuid);
250+
Mockito.when(srMock.getType(connectionMock)).thenReturn(srType);
251+
252+
Mockito.doNothing().when(srMock).setNameLabel(connectionMock, srUuid);
253+
Mockito.doNothing().when(srMock).setNameDescription(connectionMock, expectedNameDescription);
254+
255+
citrixResourceBase.configureStorageNameAndDescription(connectionMock, srMock);
256+
257+
Mockito.verify(srMock).setNameLabel(connectionMock, srUuid);
258+
Mockito.verify(srMock).setNameDescription(connectionMock, expectedNameDescription);
259+
}
260+
261+
@Test
262+
public void createStartUpStorageCommandTest() throws XenAPIException, XmlRpcException {
263+
String hostUuid = "hostUUid";
264+
citrixResourceBase._host.setUuid(hostUuid);
265+
citrixResourceBase._dcId = 1;
266+
267+
Connection connectionMock = Mockito.mock(Connection.class);
268+
SR srMock = Mockito.mock(SR.class);
269+
270+
StoragePoolInfo storagePoolInfoMock = Mockito.mock(StoragePoolInfo.class);
271+
272+
Mockito.doNothing().when(citrixResourceBase).configureStorageNameAndDescription(connectionMock, srMock);
273+
Mockito.doReturn(storagePoolInfoMock).when(citrixResourceBase).createStoragePoolInfo(connectionMock, srMock);
274+
275+
StartupStorageCommand startUpStorageCommand = citrixResourceBase.createStartUpStorageCommand(connectionMock, srMock);
276+
277+
Assert.assertEquals(hostUuid, startUpStorageCommand.getGuid());
278+
Assert.assertEquals(storagePoolInfoMock, startUpStorageCommand.getPoolInfo());
279+
Assert.assertEquals(citrixResourceBase._dcId + "", startUpStorageCommand.getDataCenter());
280+
Assert.assertEquals(StorageResourceType.STORAGE_POOL, startUpStorageCommand.getResourceType());
281+
}
282+
283+
@Test
284+
public void initializeLocalSrTest() throws XenAPIException, XmlRpcException {
285+
Connection connectionMock = Mockito.mock(Connection.class);
286+
287+
List<SR> srsMocks = new ArrayList<>();
288+
SR srMock1 = Mockito.mock(SR.class);
289+
SR srMock2 = Mockito.mock(SR.class);
290+
291+
Mockito.when(srMock1.getPhysicalSize(connectionMock)).thenReturn(0l);
292+
Mockito.when(srMock2.getPhysicalSize(connectionMock)).thenReturn(100l);
293+
srsMocks.add(srMock1);
294+
srsMocks.add(srMock2);
295+
296+
Mockito.doReturn(srsMocks).when(citrixResourceBase).getAllLocalSrs(connectionMock);
297+
298+
StartupStorageCommand startupStorageCommandMock = Mockito.mock(StartupStorageCommand.class);
299+
Mockito.doReturn(startupStorageCommandMock).when(citrixResourceBase).createStartUpStorageCommand(Mockito.eq(connectionMock), Mockito.any(SR.class));
300+
301+
List<StartupStorageCommand> startUpCommandsForLocalStorage = citrixResourceBase.initializeLocalSrs(connectionMock);
302+
303+
Mockito.verify(citrixResourceBase, Mockito.times(0)).createStartUpStorageCommand(connectionMock, srMock1);
304+
Mockito.verify(citrixResourceBase, Mockito.times(1)).createStartUpStorageCommand(connectionMock, srMock2);
305+
306+
Assert.assertEquals(1, startUpCommandsForLocalStorage.size());
307+
}
95308
}

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ cloudmonkey
2121
# Marvin dependencies are installed via its bundle
2222

2323
# Install the SolidFire SDK for Python
24-
solidfire-sdk-python
24+
solidfire-sdk-python

server/src/com/cloud/server/ManagementServerImpl.java

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,15 @@
140140
import org.apache.cloudstack.api.command.admin.offering.DeleteServiceOfferingCmd;
141141
import org.apache.cloudstack.api.command.admin.offering.UpdateDiskOfferingCmd;
142142
import org.apache.cloudstack.api.command.admin.offering.UpdateServiceOfferingCmd;
143+
import org.apache.cloudstack.api.command.admin.outofbandmanagement.ChangeOutOfBandManagementPasswordCmd;
144+
import org.apache.cloudstack.api.command.admin.outofbandmanagement.ConfigureOutOfBandManagementCmd;
143145
import org.apache.cloudstack.api.command.admin.outofbandmanagement.DisableOutOfBandManagementForClusterCmd;
144146
import org.apache.cloudstack.api.command.admin.outofbandmanagement.DisableOutOfBandManagementForHostCmd;
145147
import org.apache.cloudstack.api.command.admin.outofbandmanagement.DisableOutOfBandManagementForZoneCmd;
146148
import org.apache.cloudstack.api.command.admin.outofbandmanagement.EnableOutOfBandManagementForClusterCmd;
147149
import org.apache.cloudstack.api.command.admin.outofbandmanagement.EnableOutOfBandManagementForHostCmd;
148150
import org.apache.cloudstack.api.command.admin.outofbandmanagement.EnableOutOfBandManagementForZoneCmd;
149-
import org.apache.cloudstack.api.command.admin.outofbandmanagement.ConfigureOutOfBandManagementCmd;
150151
import org.apache.cloudstack.api.command.admin.outofbandmanagement.IssueOutOfBandManagementPowerActionCmd;
151-
import org.apache.cloudstack.api.command.admin.outofbandmanagement.ChangeOutOfBandManagementPasswordCmd;
152152
import org.apache.cloudstack.api.command.admin.pod.CreatePodCmd;
153153
import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd;
154154
import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd;
@@ -1355,11 +1355,6 @@ public Pair<List<? extends StoragePool>, List<? extends StoragePool>> listStorag
13551355
return new Pair<List<? extends StoragePool>, List<? extends StoragePool>>(allPools, suitablePools);
13561356
}
13571357

1358-
if (!_volumeMgr.volumeOnSharedStoragePool(volume)) {
1359-
s_logger.info("Volume " + volume + " is on local storage. It cannot be migrated to another pool.");
1360-
return new Pair<List<? extends StoragePool>, List<? extends StoragePool>>(allPools, suitablePools);
1361-
}
1362-
13631358
final Long instanceId = volume.getInstanceId();
13641359
VMInstanceVO vm = null;
13651360
if (instanceId != null) {
@@ -2149,7 +2144,7 @@ public GuestOS addGuestOs(final AddGuestOsCmd cmd) {
21492144
if(cmd.getDetails() != null && !cmd.getDetails().isEmpty()){
21502145
Map<String, String> detailsMap = cmd.getDetails();
21512146
for(Object key: detailsMap.keySet()){
2152-
_guestOsDetailsDao.addDetail(guestOsPersisted.getId(),(String) key,detailsMap.get((String) key), false);
2147+
_guestOsDetailsDao.addDetail(guestOsPersisted.getId(),(String) key,detailsMap.get(key), false);
21532148
}
21542149
}
21552150

@@ -2182,7 +2177,7 @@ public GuestOS updateGuestOs(final UpdateGuestOsCmd cmd) {
21822177
if(cmd.getDetails() != null && !cmd.getDetails().isEmpty()){
21832178
Map<String, String> detailsMap = cmd.getDetails();
21842179
for(Object key: detailsMap.keySet()){
2185-
_guestOsDetailsDao.addDetail(id,(String) key,detailsMap.get((String) key), false);
2180+
_guestOsDetailsDao.addDetail(id,(String) key,detailsMap.get(key), false);
21862181
}
21872182
}
21882183

0 commit comments

Comments
 (0)