Skip to content

Commit 5f93ce7

Browse files
committed
Merge branch '4.19' into 4.20
2 parents 0b7aef7 + 3afab9a commit 5f93ce7

File tree

14 files changed

+199
-186
lines changed

14 files changed

+199
-186
lines changed

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,11 @@
2828
import org.apache.cloudstack.api.EntityReference;
2929

3030
import com.cloud.network.Network;
31-
import com.cloud.projects.ProjectAccount;
3231
import com.cloud.serializer.Param;
3332
import com.google.gson.annotations.SerializedName;
3433

3534
@SuppressWarnings("unused")
36-
@EntityReference(value = {Network.class, ProjectAccount.class})
35+
@EntityReference(value = {Network.class})
3736
public class NetworkResponse extends BaseResponseWithAssociatedNetwork implements ControlledEntityResponse, SetResourceIconResponse {
3837

3938
@SerializedName(ApiConstants.ID)

engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/BasePrimaryDataStoreLifeCycleImpl.java

+51-3
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,29 @@
2222

2323
import javax.inject.Inject;
2424

25-
import com.cloud.dc.dao.DataCenterDao;
2625
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
2726
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
27+
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
28+
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
2829
import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
2930

3031
import com.cloud.agent.AgentManager;
3132
import com.cloud.agent.api.Answer;
3233
import com.cloud.agent.api.DeleteStoragePoolCommand;
34+
import com.cloud.dc.dao.DataCenterDao;
3335
import com.cloud.host.HostVO;
3436
import com.cloud.host.dao.HostDao;
3537
import com.cloud.hypervisor.Hypervisor.HypervisorType;
3638
import com.cloud.resource.ResourceManager;
3739
import com.cloud.storage.StorageManager;
3840
import com.cloud.storage.StoragePool;
3941
import com.cloud.storage.StoragePoolHostVO;
42+
import com.cloud.storage.VMTemplateStoragePoolVO;
43+
import com.cloud.storage.VMTemplateStorageResourceAssoc;
4044
import com.cloud.storage.dao.StoragePoolHostDao;
45+
import com.cloud.template.TemplateManager;
4146
import com.cloud.utils.Pair;
47+
4248
import org.apache.logging.log4j.LogManager;
4349
import org.apache.logging.log4j.Logger;
4450

@@ -59,6 +65,10 @@ public class BasePrimaryDataStoreLifeCycleImpl {
5965
protected DataCenterDao zoneDao;
6066
@Inject
6167
protected StoragePoolHostDao storagePoolHostDao;
68+
@Inject
69+
private PrimaryDataStoreDao primaryDataStoreDao;
70+
@Inject
71+
private TemplateManager templateMgr;
6272

6373
private List<HostVO> getPoolHostsList(ClusterScope clusterScope, HypervisorType hypervisorType) {
6474
List<HostVO> hosts;
@@ -81,7 +91,7 @@ public void changeStoragePoolScopeToZone(DataStore store, ClusterScope clusterSc
8191
try {
8292
storageMgr.connectHostToSharedPool(host, store.getId());
8393
} catch (Exception e) {
84-
logger.warn("Unable to establish a connection between " + host + " and " + store, e);
94+
logger.warn("Unable to establish a connection between {} and {}", host, store, e);
8595
}
8696
}
8797
}
@@ -99,7 +109,7 @@ public void changeStoragePoolScopeToCluster(DataStore store, ClusterScope cluste
99109

100110
if (answer != null) {
101111
if (!answer.getResult()) {
102-
logger.debug("Failed to delete storage pool: " + answer.getResult());
112+
logger.debug("Failed to delete storage pool: {}", answer.getResult());
103113
} else if (HypervisorType.KVM != hypervisorType) {
104114
break;
105115
}
@@ -108,4 +118,42 @@ public void changeStoragePoolScopeToCluster(DataStore store, ClusterScope cluste
108118
}
109119
dataStoreHelper.switchToCluster(store, clusterScope);
110120
}
121+
122+
private void evictTemplates(StoragePoolVO storagePoolVO) {
123+
List<VMTemplateStoragePoolVO> unusedTemplatesInPool = templateMgr.getUnusedTemplatesInPool(storagePoolVO);
124+
for (VMTemplateStoragePoolVO templatePoolVO : unusedTemplatesInPool) {
125+
if (templatePoolVO.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) {
126+
templateMgr.evictTemplateFromStoragePool(templatePoolVO);
127+
}
128+
}
129+
}
130+
131+
private void deleteAgentStoragePools(StoragePool storagePool) {
132+
List<StoragePoolHostVO> poolHostVOs = storagePoolHostDao.listByPoolId(storagePool.getId());
133+
for (StoragePoolHostVO poolHostVO : poolHostVOs) {
134+
DeleteStoragePoolCommand deleteStoragePoolCommand = new DeleteStoragePoolCommand(storagePool);
135+
final Answer answer = agentMgr.easySend(poolHostVO.getHostId(), deleteStoragePoolCommand);
136+
if (answer != null && answer.getResult()) {
137+
logger.info("Successfully deleted storage pool: {} from host: {}", storagePool.getId(), poolHostVO.getHostId());
138+
} else {
139+
if (answer != null) {
140+
logger.error("Failed to delete storage pool: {} from host: {} , result: {}", storagePool.getId(), poolHostVO.getHostId(), answer.getResult());
141+
} else {
142+
logger.error("Failed to delete storage pool: {} from host: {}", storagePool.getId(), poolHostVO.getHostId());
143+
}
144+
}
145+
}
146+
}
147+
148+
protected boolean cleanupDatastore(DataStore store) {
149+
StoragePool storagePool = (StoragePool)store;
150+
StoragePoolVO storagePoolVO = primaryDataStoreDao.findById(storagePool.getId());
151+
if (storagePoolVO == null) {
152+
return false;
153+
}
154+
155+
evictTemplates(storagePoolVO);
156+
deleteAgentStoragePools(storagePool);
157+
return true;
158+
}
111159
}

plugins/storage/volume/linstor/CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to Linstor CloudStack plugin will be documented in this file
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [2025-03-13]
9+
10+
### Fixed
11+
12+
- Implemented missing delete datastore, to correctly cleanup on datastore removal
13+
814
## [2025-02-21]
915

1016
### Fixed

plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/LinstorPrimaryDataStoreLifeCycleImpl.java

+4-1
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,10 @@ public boolean cancelMaintain(DataStore store) {
286286

287287
@Override
288288
public boolean deleteDataStore(DataStore store) {
289-
return dataStoreHelper.deletePrimaryDataStore(store);
289+
if (cleanupDatastore(store)) {
290+
return dataStoreHelper.deletePrimaryDataStore(store);
291+
}
292+
return false;
290293
}
291294

292295
/* (non-Javadoc)

plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycle.java

+10-45
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
*/
1919
package org.apache.cloudstack.storage.datastore.lifecycle;
2020

21-
import java.io.UnsupportedEncodingException;
2221
import java.net.URI;
2322
import java.net.URISyntaxException;
2423
import java.net.URLDecoder;
@@ -30,6 +29,7 @@
3029

3130
import javax.inject.Inject;
3231

32+
import com.cloud.utils.StringUtils;
3333
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
3434
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
3535
import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
@@ -48,8 +48,6 @@
4848
import org.apache.commons.collections.CollectionUtils;
4949

5050
import com.cloud.agent.AgentManager;
51-
import com.cloud.agent.api.Answer;
52-
import com.cloud.agent.api.DeleteStoragePoolCommand;
5351
import com.cloud.agent.api.StoragePoolInfo;
5452
import com.cloud.capacity.CapacityManager;
5553
import com.cloud.dc.ClusterVO;
@@ -63,9 +61,6 @@
6361
import com.cloud.storage.StorageManager;
6462
import com.cloud.storage.StoragePool;
6563
import com.cloud.storage.StoragePoolAutomation;
66-
import com.cloud.storage.StoragePoolHostVO;
67-
import com.cloud.storage.VMTemplateStoragePoolVO;
68-
import com.cloud.storage.VMTemplateStorageResourceAssoc;
6964
import com.cloud.storage.dao.StoragePoolHostDao;
7065
import com.cloud.template.TemplateManager;
7166
import com.cloud.utils.UriUtils;
@@ -111,7 +106,7 @@ private org.apache.cloudstack.storage.datastore.api.StoragePool findStoragePool(
111106
List<org.apache.cloudstack.storage.datastore.api.StoragePool> storagePools = client.listStoragePools();
112107
for (org.apache.cloudstack.storage.datastore.api.StoragePool pool : storagePools) {
113108
if (pool.getName().equals(storagePoolName)) {
114-
logger.info("Found PowerFlex storage pool: " + storagePoolName);
109+
logger.info("Found PowerFlex storage pool: {}", storagePoolName);
115110
final org.apache.cloudstack.storage.datastore.api.StoragePoolStatistics poolStatistics = client.getStoragePoolStatistics(pool.getId());
116111
pool.setStatistics(poolStatistics);
117112

@@ -164,7 +159,7 @@ public DataStore initialize(Map<String, Object> dsInfos) {
164159
throw new CloudRuntimeException("Cluster Id must also be specified when the Pod Id is specified for Cluster-wide primary storage.");
165160
}
166161

167-
URI uri = null;
162+
URI uri;
168163
try {
169164
uri = new URI(UriUtils.encodeURIComponent(url));
170165
if (uri.getScheme() == null || !uri.getScheme().equalsIgnoreCase("powerflex")) {
@@ -174,20 +169,16 @@ public DataStore initialize(Map<String, Object> dsInfos) {
174169
throw new InvalidParameterValueException(url + " is not a valid uri");
175170
}
176171

177-
String storagePoolName = null;
178-
try {
179-
storagePoolName = URLDecoder.decode(uri.getPath(), "UTF-8");
180-
} catch (UnsupportedEncodingException e) {
181-
logger.error("[ignored] we are on a platform not supporting \"UTF-8\"!?!", e);
182-
}
172+
String storagePoolName;
173+
storagePoolName = URLDecoder.decode(uri.getPath(), StringUtils.getPreferredCharset());
183174
if (storagePoolName == null) { // if decoding fails, use getPath() anyway
184175
storagePoolName = uri.getPath();
185176
}
186177
storagePoolName = storagePoolName.replaceFirst("/", "");
187178

188179
final String storageHost = uri.getHost();
189180
final int port = uri.getPort();
190-
String gatewayApiURL = null;
181+
String gatewayApiURL;
191182
if (port == -1) {
192183
gatewayApiURL = String.format("https://%s/api", storageHost);
193184
} else {
@@ -321,37 +312,11 @@ public void disableStoragePool(DataStore dataStore) {
321312

322313
@Override
323314
public boolean deleteDataStore(DataStore dataStore) {
324-
StoragePool storagePool = (StoragePool)dataStore;
325-
StoragePoolVO storagePoolVO = primaryDataStoreDao.findById(storagePool.getId());
326-
if (storagePoolVO == null) {
327-
return false;
315+
if (cleanupDatastore(dataStore)) {
316+
ScaleIOGatewayClientConnectionPool.getInstance().removeClient(dataStore);
317+
return dataStoreHelper.deletePrimaryDataStore(dataStore);
328318
}
329-
330-
List<VMTemplateStoragePoolVO> unusedTemplatesInPool = templateMgr.getUnusedTemplatesInPool(storagePoolVO);
331-
for (VMTemplateStoragePoolVO templatePoolVO : unusedTemplatesInPool) {
332-
if (templatePoolVO.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) {
333-
templateMgr.evictTemplateFromStoragePool(templatePoolVO);
334-
}
335-
}
336-
337-
List<StoragePoolHostVO> poolHostVOs = storagePoolHostDao.listByPoolId(dataStore.getId());
338-
for (StoragePoolHostVO poolHostVO : poolHostVOs) {
339-
DeleteStoragePoolCommand deleteStoragePoolCommand = new DeleteStoragePoolCommand(storagePool);
340-
final Answer answer = agentMgr.easySend(poolHostVO.getHostId(), deleteStoragePoolCommand);
341-
if (answer != null && answer.getResult()) {
342-
logger.info("Successfully deleted storage pool: {} from host: {}", storagePool, poolHostVO.getHostId());
343-
} else {
344-
if (answer != null) {
345-
logger.error("Failed to delete storage pool: {} from host: {} , result: {}", storagePool, poolHostVO.getHostId(), answer.getResult());
346-
} else {
347-
logger.error("Failed to delete storage pool: {} from host: {}", storagePool, poolHostVO.getHostId());
348-
}
349-
}
350-
}
351-
352-
ScaleIOGatewayClientConnectionPool.getInstance().removeClient(dataStore);
353-
354-
return dataStoreHelper.deletePrimaryDataStore(dataStore);
319+
return false;
355320
}
356321

357322
@Override

scripts/storage/secondary/setup-sysvm-tmplt

+5-5
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ if [[ -f $destdir/template.properties ]]; then
9999
failed 2 "Data already exists at destination $destdir"
100100
fi
101101

102-
destfiles=$(find $destdir -name \*.$ext)
102+
destfiles=$(sudo find $destdir -name \*.$ext)
103103
if [[ "$destfiles" != "" ]]; then
104104
failed 2 "Data already exists at destination $destdir"
105105
fi
@@ -108,12 +108,12 @@ tmpfolder=/tmp/cloud/templates/
108108
mkdir -p $tmpfolder
109109
tmplfile=$tmpfolder/$localfile
110110

111-
sudo touch $tmplfile
111+
touch $tmplfile
112112
if [[ $? -ne 0 ]]; then
113113
failed 2 "Failed to create temporary file in directory $tmpfolder -- is it read-only or full?\n"
114114
fi
115115

116-
destcap=$(df -P $destdir | awk '{print $4}' | tail -1 )
116+
destcap=$(sudo df -P $destdir | awk '{print $4}' | tail -1 )
117117
[ $destcap -lt $DISKSPACE ] && echo "Insufficient free disk space for target folder $destdir: avail=${destcap}k req=${DISKSPACE}k" && failed 4
118118

119119
localcap=$(df -P $tmpfolder | awk '{print $4}' | tail -1 )
@@ -146,9 +146,9 @@ fi
146146

147147

148148
tmpltfile=$destdir/$localfile
149-
tmpltsize=$(ls -l $tmpltfile | awk -F" " '{print $5}')
149+
tmpltsize=$(sudo ls -l $tmpltfile | awk -F" " '{print $5}')
150150
if [[ "$ext" == "qcow2" ]]; then
151-
vrtmpltsize=$($qemuimgcmd info $tmpltfile | grep -i 'virtual size' | sed -ne 's/.*(\([0-9]*\).*/\1/p' | xargs)
151+
vrtmpltsize=$(sudo $qemuimgcmd info $tmpltfile | grep -i 'virtual size' | sed -ne 's/.*(\([0-9]*\).*/\1/p' | xargs)
152152
else
153153
vrtmpltsize=$tmpltsize
154154
fi

server/conf/cloudstack-sudoers.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
# The CloudStack management server needs sudo permissions
1919
# without a password.
2020

21-
Cmnd_Alias CLOUDSTACK = /bin/mkdir, /bin/mount, /bin/umount, /bin/cp, /bin/chmod, /usr/bin/keytool, /bin/keytool, /bin/touch
21+
Cmnd_Alias CLOUDSTACK = /bin/mkdir, /bin/mount, /bin/umount, /bin/cp, /bin/chmod, /usr/bin/keytool, /bin/keytool, /bin/touch, /bin/find, /bin/df, /bin/ls, /bin/qemu-img
2222

2323
Defaults:@MSUSER@ !requiretty
2424

server/src/main/java/com/cloud/network/router/NetworkHelperImpl.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,9 @@ public DomainRouterVO startVirtualRouter(final DomainRouterVO router, final User
446446
final int retryIndex = 5;
447447
final ExcludeList[] avoids = new ExcludeList[5];
448448
avoids[0] = new ExcludeList();
449-
avoids[0].addPod(routerToBeAvoid.getPodIdToDeployIn());
449+
if (routerToBeAvoid.getPodIdToDeployIn() != null) {
450+
avoids[0].addPod(routerToBeAvoid.getPodIdToDeployIn());
451+
}
450452
avoids[1] = new ExcludeList();
451453
avoids[1].addCluster(_hostDao.findById(routerToBeAvoid.getHostId()).getClusterId());
452454
avoids[2] = new ExcludeList();

0 commit comments

Comments
 (0)