Merge branch '4.19' into 4.20

This commit is contained in:
Daan Hoogland 2025-03-27 16:44:42 +01:00
commit 5f93ce71bb
14 changed files with 199 additions and 186 deletions

View File

@ -28,12 +28,11 @@ import org.apache.cloudstack.api.BaseResponseWithAssociatedNetwork;
import org.apache.cloudstack.api.EntityReference; import org.apache.cloudstack.api.EntityReference;
import com.cloud.network.Network; import com.cloud.network.Network;
import com.cloud.projects.ProjectAccount;
import com.cloud.serializer.Param; import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName; import com.google.gson.annotations.SerializedName;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@EntityReference(value = {Network.class, ProjectAccount.class}) @EntityReference(value = {Network.class})
public class NetworkResponse extends BaseResponseWithAssociatedNetwork implements ControlledEntityResponse, SetResourceIconResponse { public class NetworkResponse extends BaseResponseWithAssociatedNetwork implements ControlledEntityResponse, SetResourceIconResponse {
@SerializedName(ApiConstants.ID) @SerializedName(ApiConstants.ID)

View File

@ -22,14 +22,16 @@ import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import com.cloud.dc.dao.DataCenterDao;
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper; import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer; import com.cloud.agent.api.Answer;
import com.cloud.agent.api.DeleteStoragePoolCommand; import com.cloud.agent.api.DeleteStoragePoolCommand;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.host.HostVO; import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao; import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.hypervisor.Hypervisor.HypervisorType;
@ -37,8 +39,12 @@ import com.cloud.resource.ResourceManager;
import com.cloud.storage.StorageManager; import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolHostVO; import com.cloud.storage.StoragePoolHostVO;
import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.template.TemplateManager;
import com.cloud.utils.Pair; import com.cloud.utils.Pair;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
@ -59,6 +65,10 @@ public class BasePrimaryDataStoreLifeCycleImpl {
protected DataCenterDao zoneDao; protected DataCenterDao zoneDao;
@Inject @Inject
protected StoragePoolHostDao storagePoolHostDao; protected StoragePoolHostDao storagePoolHostDao;
@Inject
private PrimaryDataStoreDao primaryDataStoreDao;
@Inject
private TemplateManager templateMgr;
private List<HostVO> getPoolHostsList(ClusterScope clusterScope, HypervisorType hypervisorType) { private List<HostVO> getPoolHostsList(ClusterScope clusterScope, HypervisorType hypervisorType) {
List<HostVO> hosts; List<HostVO> hosts;
@ -81,7 +91,7 @@ public class BasePrimaryDataStoreLifeCycleImpl {
try { try {
storageMgr.connectHostToSharedPool(host, store.getId()); storageMgr.connectHostToSharedPool(host, store.getId());
} catch (Exception e) { } catch (Exception e) {
logger.warn("Unable to establish a connection between " + host + " and " + store, e); logger.warn("Unable to establish a connection between {} and {}", host, store, e);
} }
} }
} }
@ -99,7 +109,7 @@ public class BasePrimaryDataStoreLifeCycleImpl {
if (answer != null) { if (answer != null) {
if (!answer.getResult()) { if (!answer.getResult()) {
logger.debug("Failed to delete storage pool: " + answer.getResult()); logger.debug("Failed to delete storage pool: {}", answer.getResult());
} else if (HypervisorType.KVM != hypervisorType) { } else if (HypervisorType.KVM != hypervisorType) {
break; break;
} }
@ -108,4 +118,42 @@ public class BasePrimaryDataStoreLifeCycleImpl {
} }
dataStoreHelper.switchToCluster(store, clusterScope); dataStoreHelper.switchToCluster(store, clusterScope);
} }
private void evictTemplates(StoragePoolVO storagePoolVO) {
List<VMTemplateStoragePoolVO> unusedTemplatesInPool = templateMgr.getUnusedTemplatesInPool(storagePoolVO);
for (VMTemplateStoragePoolVO templatePoolVO : unusedTemplatesInPool) {
if (templatePoolVO.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) {
templateMgr.evictTemplateFromStoragePool(templatePoolVO);
}
}
}
private void deleteAgentStoragePools(StoragePool storagePool) {
List<StoragePoolHostVO> poolHostVOs = storagePoolHostDao.listByPoolId(storagePool.getId());
for (StoragePoolHostVO poolHostVO : poolHostVOs) {
DeleteStoragePoolCommand deleteStoragePoolCommand = new DeleteStoragePoolCommand(storagePool);
final Answer answer = agentMgr.easySend(poolHostVO.getHostId(), deleteStoragePoolCommand);
if (answer != null && answer.getResult()) {
logger.info("Successfully deleted storage pool: {} from host: {}", storagePool.getId(), poolHostVO.getHostId());
} else {
if (answer != null) {
logger.error("Failed to delete storage pool: {} from host: {} , result: {}", storagePool.getId(), poolHostVO.getHostId(), answer.getResult());
} else {
logger.error("Failed to delete storage pool: {} from host: {}", storagePool.getId(), poolHostVO.getHostId());
}
}
}
}
protected boolean cleanupDatastore(DataStore store) {
StoragePool storagePool = (StoragePool)store;
StoragePoolVO storagePoolVO = primaryDataStoreDao.findById(storagePool.getId());
if (storagePoolVO == null) {
return false;
}
evictTemplates(storagePoolVO);
deleteAgentStoragePools(storagePool);
return true;
}
} }

View File

@ -5,6 +5,12 @@ All notable changes to Linstor CloudStack plugin will be documented in this file
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2025-03-13]
### Fixed
- Implemented missing delete datastore, to correctly cleanup on datastore removal
## [2025-02-21] ## [2025-02-21]
### Fixed ### Fixed

View File

@ -286,7 +286,10 @@ public class LinstorPrimaryDataStoreLifeCycleImpl extends BasePrimaryDataStoreLi
@Override @Override
public boolean deleteDataStore(DataStore store) { public boolean deleteDataStore(DataStore store) {
return dataStoreHelper.deletePrimaryDataStore(store); if (cleanupDatastore(store)) {
return dataStoreHelper.deletePrimaryDataStore(store);
}
return false;
} }
/* (non-Javadoc) /* (non-Javadoc)

View File

@ -18,7 +18,6 @@
*/ */
package org.apache.cloudstack.storage.datastore.lifecycle; package org.apache.cloudstack.storage.datastore.lifecycle;
import java.io.UnsupportedEncodingException;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.net.URLDecoder; import java.net.URLDecoder;
@ -30,6 +29,7 @@ import java.util.UUID;
import javax.inject.Inject; import javax.inject.Inject;
import com.cloud.utils.StringUtils;
import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope; import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
import org.apache.cloudstack.engine.subsystem.api.storage.DataStore; import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
import org.apache.cloudstack.engine.subsystem.api.storage.HostScope; import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
@ -48,8 +48,6 @@ import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.DeleteStoragePoolCommand;
import com.cloud.agent.api.StoragePoolInfo; import com.cloud.agent.api.StoragePoolInfo;
import com.cloud.capacity.CapacityManager; import com.cloud.capacity.CapacityManager;
import com.cloud.dc.ClusterVO; import com.cloud.dc.ClusterVO;
@ -63,9 +61,6 @@ import com.cloud.storage.Storage;
import com.cloud.storage.StorageManager; import com.cloud.storage.StorageManager;
import com.cloud.storage.StoragePool; import com.cloud.storage.StoragePool;
import com.cloud.storage.StoragePoolAutomation; import com.cloud.storage.StoragePoolAutomation;
import com.cloud.storage.StoragePoolHostVO;
import com.cloud.storage.VMTemplateStoragePoolVO;
import com.cloud.storage.VMTemplateStorageResourceAssoc;
import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.template.TemplateManager; import com.cloud.template.TemplateManager;
import com.cloud.utils.UriUtils; import com.cloud.utils.UriUtils;
@ -111,7 +106,7 @@ public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCy
List<org.apache.cloudstack.storage.datastore.api.StoragePool> storagePools = client.listStoragePools(); List<org.apache.cloudstack.storage.datastore.api.StoragePool> storagePools = client.listStoragePools();
for (org.apache.cloudstack.storage.datastore.api.StoragePool pool : storagePools) { for (org.apache.cloudstack.storage.datastore.api.StoragePool pool : storagePools) {
if (pool.getName().equals(storagePoolName)) { if (pool.getName().equals(storagePoolName)) {
logger.info("Found PowerFlex storage pool: " + storagePoolName); logger.info("Found PowerFlex storage pool: {}", storagePoolName);
final org.apache.cloudstack.storage.datastore.api.StoragePoolStatistics poolStatistics = client.getStoragePoolStatistics(pool.getId()); final org.apache.cloudstack.storage.datastore.api.StoragePoolStatistics poolStatistics = client.getStoragePoolStatistics(pool.getId());
pool.setStatistics(poolStatistics); pool.setStatistics(poolStatistics);
@ -164,7 +159,7 @@ public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCy
throw new CloudRuntimeException("Cluster Id must also be specified when the Pod Id is specified for Cluster-wide primary storage."); throw new CloudRuntimeException("Cluster Id must also be specified when the Pod Id is specified for Cluster-wide primary storage.");
} }
URI uri = null; URI uri;
try { try {
uri = new URI(UriUtils.encodeURIComponent(url)); uri = new URI(UriUtils.encodeURIComponent(url));
if (uri.getScheme() == null || !uri.getScheme().equalsIgnoreCase("powerflex")) { if (uri.getScheme() == null || !uri.getScheme().equalsIgnoreCase("powerflex")) {
@ -174,12 +169,8 @@ public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCy
throw new InvalidParameterValueException(url + " is not a valid uri"); throw new InvalidParameterValueException(url + " is not a valid uri");
} }
String storagePoolName = null; String storagePoolName;
try { storagePoolName = URLDecoder.decode(uri.getPath(), StringUtils.getPreferredCharset());
storagePoolName = URLDecoder.decode(uri.getPath(), "UTF-8");
} catch (UnsupportedEncodingException e) {
logger.error("[ignored] we are on a platform not supporting \"UTF-8\"!?!", e);
}
if (storagePoolName == null) { // if decoding fails, use getPath() anyway if (storagePoolName == null) { // if decoding fails, use getPath() anyway
storagePoolName = uri.getPath(); storagePoolName = uri.getPath();
} }
@ -187,7 +178,7 @@ public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCy
final String storageHost = uri.getHost(); final String storageHost = uri.getHost();
final int port = uri.getPort(); final int port = uri.getPort();
String gatewayApiURL = null; String gatewayApiURL;
if (port == -1) { if (port == -1) {
gatewayApiURL = String.format("https://%s/api", storageHost); gatewayApiURL = String.format("https://%s/api", storageHost);
} else { } else {
@ -321,37 +312,11 @@ public class ScaleIOPrimaryDataStoreLifeCycle extends BasePrimaryDataStoreLifeCy
@Override @Override
public boolean deleteDataStore(DataStore dataStore) { public boolean deleteDataStore(DataStore dataStore) {
StoragePool storagePool = (StoragePool)dataStore; if (cleanupDatastore(dataStore)) {
StoragePoolVO storagePoolVO = primaryDataStoreDao.findById(storagePool.getId()); ScaleIOGatewayClientConnectionPool.getInstance().removeClient(dataStore);
if (storagePoolVO == null) { return dataStoreHelper.deletePrimaryDataStore(dataStore);
return false;
} }
return false;
List<VMTemplateStoragePoolVO> unusedTemplatesInPool = templateMgr.getUnusedTemplatesInPool(storagePoolVO);
for (VMTemplateStoragePoolVO templatePoolVO : unusedTemplatesInPool) {
if (templatePoolVO.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED) {
templateMgr.evictTemplateFromStoragePool(templatePoolVO);
}
}
List<StoragePoolHostVO> poolHostVOs = storagePoolHostDao.listByPoolId(dataStore.getId());
for (StoragePoolHostVO poolHostVO : poolHostVOs) {
DeleteStoragePoolCommand deleteStoragePoolCommand = new DeleteStoragePoolCommand(storagePool);
final Answer answer = agentMgr.easySend(poolHostVO.getHostId(), deleteStoragePoolCommand);
if (answer != null && answer.getResult()) {
logger.info("Successfully deleted storage pool: {} from host: {}", storagePool, poolHostVO.getHostId());
} else {
if (answer != null) {
logger.error("Failed to delete storage pool: {} from host: {} , result: {}", storagePool, poolHostVO.getHostId(), answer.getResult());
} else {
logger.error("Failed to delete storage pool: {} from host: {}", storagePool, poolHostVO.getHostId());
}
}
}
ScaleIOGatewayClientConnectionPool.getInstance().removeClient(dataStore);
return dataStoreHelper.deletePrimaryDataStore(dataStore);
} }
@Override @Override

View File

@ -99,7 +99,7 @@ if [[ -f $destdir/template.properties ]]; then
failed 2 "Data already exists at destination $destdir" failed 2 "Data already exists at destination $destdir"
fi fi
destfiles=$(find $destdir -name \*.$ext) destfiles=$(sudo find $destdir -name \*.$ext)
if [[ "$destfiles" != "" ]]; then if [[ "$destfiles" != "" ]]; then
failed 2 "Data already exists at destination $destdir" failed 2 "Data already exists at destination $destdir"
fi fi
@ -108,12 +108,12 @@ tmpfolder=/tmp/cloud/templates/
mkdir -p $tmpfolder mkdir -p $tmpfolder
tmplfile=$tmpfolder/$localfile tmplfile=$tmpfolder/$localfile
sudo touch $tmplfile touch $tmplfile
if [[ $? -ne 0 ]]; then if [[ $? -ne 0 ]]; then
failed 2 "Failed to create temporary file in directory $tmpfolder -- is it read-only or full?\n" failed 2 "Failed to create temporary file in directory $tmpfolder -- is it read-only or full?\n"
fi fi
destcap=$(df -P $destdir | awk '{print $4}' | tail -1 ) destcap=$(sudo df -P $destdir | awk '{print $4}' | tail -1 )
[ $destcap -lt $DISKSPACE ] && echo "Insufficient free disk space for target folder $destdir: avail=${destcap}k req=${DISKSPACE}k" && failed 4 [ $destcap -lt $DISKSPACE ] && echo "Insufficient free disk space for target folder $destdir: avail=${destcap}k req=${DISKSPACE}k" && failed 4
localcap=$(df -P $tmpfolder | awk '{print $4}' | tail -1 ) localcap=$(df -P $tmpfolder | awk '{print $4}' | tail -1 )
@ -146,9 +146,9 @@ fi
tmpltfile=$destdir/$localfile tmpltfile=$destdir/$localfile
tmpltsize=$(ls -l $tmpltfile | awk -F" " '{print $5}') tmpltsize=$(sudo ls -l $tmpltfile | awk -F" " '{print $5}')
if [[ "$ext" == "qcow2" ]]; then if [[ "$ext" == "qcow2" ]]; then
vrtmpltsize=$($qemuimgcmd info $tmpltfile | grep -i 'virtual size' | sed -ne 's/.*(\([0-9]*\).*/\1/p' | xargs) vrtmpltsize=$(sudo $qemuimgcmd info $tmpltfile | grep -i 'virtual size' | sed -ne 's/.*(\([0-9]*\).*/\1/p' | xargs)
else else
vrtmpltsize=$tmpltsize vrtmpltsize=$tmpltsize
fi fi

View File

@ -18,7 +18,7 @@
# The CloudStack management server needs sudo permissions # The CloudStack management server needs sudo permissions
# without a password. # without a password.
Cmnd_Alias CLOUDSTACK = /bin/mkdir, /bin/mount, /bin/umount, /bin/cp, /bin/chmod, /usr/bin/keytool, /bin/keytool, /bin/touch 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
Defaults:@MSUSER@ !requiretty Defaults:@MSUSER@ !requiretty

View File

@ -446,7 +446,9 @@ public class NetworkHelperImpl implements NetworkHelper {
final int retryIndex = 5; final int retryIndex = 5;
final ExcludeList[] avoids = new ExcludeList[5]; final ExcludeList[] avoids = new ExcludeList[5];
avoids[0] = new ExcludeList(); avoids[0] = new ExcludeList();
avoids[0].addPod(routerToBeAvoid.getPodIdToDeployIn()); if (routerToBeAvoid.getPodIdToDeployIn() != null) {
avoids[0].addPod(routerToBeAvoid.getPodIdToDeployIn());
}
avoids[1] = new ExcludeList(); avoids[1] = new ExcludeList();
avoids[1].addCluster(_hostDao.findById(routerToBeAvoid.getHostId()).getClusterId()); avoids[1].addCluster(_hostDao.findById(routerToBeAvoid.getHostId()).getClusterId());
avoids[2] = new ExcludeList(); avoids[2] = new ExcludeList();

View File

@ -60,9 +60,10 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.utils.identity.ManagementServerNode; import org.apache.cloudstack.utils.identity.ManagementServerNode;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.cloud.agent.AgentManager; import com.cloud.agent.AgentManager;
@ -92,7 +93,6 @@ import com.cloud.capacity.CapacityVO;
import com.cloud.capacity.dao.CapacityDao; import com.cloud.capacity.dao.CapacityDao;
import com.cloud.cluster.ClusterManager; import com.cloud.cluster.ClusterManager;
import com.cloud.configuration.Config; import com.cloud.configuration.Config;
import com.cloud.configuration.ConfigurationManager;
import com.cloud.cpu.CPU; import com.cloud.cpu.CPU;
import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterDetailsDao;
import com.cloud.dc.ClusterDetailsVO; import com.cloud.dc.ClusterDetailsVO;
@ -125,7 +125,6 @@ import com.cloud.exception.DiscoveryException;
import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.exception.InsufficientServerCapacityException;
import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException; import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceInUseException;
import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.StorageConflictException; import com.cloud.exception.StorageConflictException;
import com.cloud.exception.StorageUnavailableException; import com.cloud.exception.StorageUnavailableException;
@ -170,7 +169,6 @@ import com.cloud.storage.StorageService;
import com.cloud.storage.VMTemplateVO; import com.cloud.storage.VMTemplateVO;
import com.cloud.storage.Volume; import com.cloud.storage.Volume;
import com.cloud.storage.VolumeVO; import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.DiskOfferingDao;
import com.cloud.storage.dao.GuestOSCategoryDao; import com.cloud.storage.dao.GuestOSCategoryDao;
import com.cloud.storage.dao.StoragePoolHostDao; import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.storage.dao.VMTemplateDao; import com.cloud.storage.dao.VMTemplateDao;
@ -203,6 +201,7 @@ import com.cloud.utils.net.NetUtils;
import com.cloud.utils.ssh.SSHCmdHelper; import com.cloud.utils.ssh.SSHCmdHelper;
import com.cloud.utils.ssh.SshException; import com.cloud.utils.ssh.SshException;
import com.cloud.vm.UserVmManager; import com.cloud.vm.UserVmManager;
import com.cloud.utils.StringUtils;
import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachine.State;
@ -236,8 +235,6 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
@Inject @Inject
private CapacityDao _capacityDao; private CapacityDao _capacityDao;
@Inject @Inject
private DiskOfferingDao diskOfferingDao;
@Inject
private ServiceOfferingDao serviceOfferingDao; private ServiceOfferingDao serviceOfferingDao;
@Inject @Inject
private HostDao _hostDao; private HostDao _hostDao;
@ -296,8 +293,6 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
@Inject @Inject
private VMTemplateDao _templateDao; private VMTemplateDao _templateDao;
@Inject @Inject
private ConfigurationManager _configMgr;
@Inject
private ClusterVSMMapDao _clusterVSMMapDao; private ClusterVSMMapDao _clusterVSMMapDao;
@Inject @Inject
private UserVmDetailsDao userVmDetailsDao; private UserVmDetailsDao userVmDetailsDao;
@ -312,9 +307,9 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
private final long _nodeId = ManagementServerNode.getManagementServerId(); private final long _nodeId = ManagementServerNode.getManagementServerId();
private final HashMap<String, ResourceStateAdapter> _resourceStateAdapters = new HashMap<String, ResourceStateAdapter>(); private final HashMap<String, ResourceStateAdapter> _resourceStateAdapters = new HashMap<>();
private final HashMap<Integer, List<ResourceListener>> _lifeCycleListeners = new HashMap<Integer, List<ResourceListener>>(); private final HashMap<Integer, List<ResourceListener>> _lifeCycleListeners = new HashMap<>();
private HypervisorType _defaultSystemVMHypervisor; private HypervisorType _defaultSystemVMHypervisor;
private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 30; // seconds private static final int ACQUIRE_GLOBAL_LOCK_TIMEOUT_FOR_COOPERATION = 30; // seconds
@ -324,11 +319,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
private SearchBuilder<HostGpuGroupsVO> _gpuAvailability; private SearchBuilder<HostGpuGroupsVO> _gpuAvailability;
private void insertListener(final Integer event, final ResourceListener listener) { private void insertListener(final Integer event, final ResourceListener listener) {
List<ResourceListener> lst = _lifeCycleListeners.get(event); List<ResourceListener> lst = _lifeCycleListeners.computeIfAbsent(event, k -> new ArrayList<>());
if (lst == null) {
lst = new ArrayList<ResourceListener>();
_lifeCycleListeners.put(event, lst);
}
if (lst.contains(listener)) { if (lst.contains(listener)) {
throw new CloudRuntimeException("Duplicate resource lisener:" + listener.getClass().getSimpleName()); throw new CloudRuntimeException("Duplicate resource lisener:" + listener.getClass().getSimpleName());
@ -370,9 +361,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
@Override @Override
public void unregisterResourceEvent(final ResourceListener listener) { public void unregisterResourceEvent(final ResourceListener listener) {
synchronized (_lifeCycleListeners) { synchronized (_lifeCycleListeners) {
final Iterator it = _lifeCycleListeners.entrySet().iterator(); for (Map.Entry<Integer, List<ResourceListener>> items : _lifeCycleListeners.entrySet()) {
while (it.hasNext()) {
final Map.Entry<Integer, List<ResourceListener>> items = (Map.Entry<Integer, List<ResourceListener>>)it.next();
final List<ResourceListener> lst = items.getValue(); final List<ResourceListener> lst = items.getValue();
lst.remove(listener); lst.remove(listener);
} }
@ -381,7 +370,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
protected void processResourceEvent(final Integer event, final Object... params) { protected void processResourceEvent(final Integer event, final Object... params) {
final List<ResourceListener> lst = _lifeCycleListeners.get(event); final List<ResourceListener> lst = _lifeCycleListeners.get(event);
if (lst == null || lst.size() == 0) { if (lst == null || lst.isEmpty()) {
return; return;
} }
@ -422,7 +411,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
@DB @DB
@Override @Override
public List<? extends Cluster> discoverCluster(final AddClusterCmd cmd) throws IllegalArgumentException, DiscoveryException, ResourceInUseException { public List<? extends Cluster> discoverCluster(final AddClusterCmd cmd) throws IllegalArgumentException, DiscoveryException {
final long dcId = cmd.getZoneId(); final long dcId = cmd.getZoneId();
final long podId = cmd.getPodId(); final long podId = cmd.getPodId();
final String clusterName = cmd.getClusterName(); final String clusterName = cmd.getClusterName();
@ -432,10 +421,10 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
CPU.CPUArch arch = cmd.getArch(); CPU.CPUArch arch = cmd.getArch();
if (url != null) { if (url != null) {
url = URLDecoder.decode(url); url = URLDecoder.decode(url, com.cloud.utils.StringUtils.getPreferredCharset());
} }
URI uri = null; URI uri;
// Check if the zone exists in the system // Check if the zone exists in the system
final DataCenterVO zone = _dcDao.findById(dcId); final DataCenterVO zone = _dcDao.findById(dcId);
@ -519,7 +508,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
discoverer.putParam(allParams); discoverer.putParam(allParams);
} }
final List<ClusterVO> result = new ArrayList<ClusterVO>(); final List<ClusterVO> result = new ArrayList<>();
ClusterVO cluster = new ClusterVO(dcId, podId, clusterName); ClusterVO cluster = new ClusterVO(dcId, podId, clusterName);
cluster.setHypervisorType(hypervisorType.toString()); cluster.setHypervisorType(hypervisorType.toString());
@ -540,7 +529,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
result.add(cluster); result.add(cluster);
if (clusterType == Cluster.ClusterType.CloudManaged) { if (clusterType == Cluster.ClusterType.CloudManaged) {
final Map<String, String> details = new HashMap<String, String>(); final Map<String, String> details = new HashMap<>();
// should do this nicer perhaps ? // should do this nicer perhaps ?
if (hypervisorType == HypervisorType.Ovm3) { if (hypervisorType == HypervisorType.Ovm3) {
final Map<String, String> allParams = cmd.getFullUrlParams(); final Map<String, String> allParams = cmd.getFullUrlParams();
@ -578,8 +567,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
throw new InvalidParameterValueException(url + " is not a valid uri"); throw new InvalidParameterValueException(url + " is not a valid uri");
} }
final List<HostVO> hosts = new ArrayList<HostVO>(); final List<HostVO> hosts = new ArrayList<>();
Map<? extends ServerResource, Map<String, String>> resources = null; Map<? extends ServerResource, Map<String, String>> resources;
resources = discoverer.find(dcId, podId, cluster.getId(), uri, username, password, null); resources = discoverer.find(dcId, podId, cluster.getId(), uri, username, password, null);
if (resources != null) { if (resources != null) {
@ -670,7 +659,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
private List<HostVO> discoverHostsFull(final Long dcId, final Long podId, Long clusterId, final String clusterName, String url, String username, String password, private List<HostVO> discoverHostsFull(final Long dcId, final Long podId, Long clusterId, final String clusterName, String url, String username, String password,
final String hypervisorType, final List<String> hostTags, final Map<String, String> params, final boolean deferAgentCreation) throws IllegalArgumentException, DiscoveryException, final String hypervisorType, final List<String> hostTags, final Map<String, String> params, final boolean deferAgentCreation) throws IllegalArgumentException, DiscoveryException,
InvalidParameterValueException { InvalidParameterValueException {
URI uri = null; URI uri;
// Check if the zone exists in the system // Check if the zone exists in the system
final DataCenterVO zone = _dcDao.findById(dcId); final DataCenterVO zone = _dcDao.findById(dcId);
@ -810,7 +799,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
throw new InvalidParameterValueException(url + " is not a valid uri"); throw new InvalidParameterValueException(url + " is not a valid uri");
} }
final List<HostVO> hosts = new ArrayList<HostVO>(); final List<HostVO> hosts = new ArrayList<>();
logger.info("Trying to add a new host at {} in data center {}", url, zone); logger.info("Trying to add a new host at {} in data center {}", url, zone);
boolean isHypervisorTypeSupported = false; boolean isHypervisorTypeSupported = false;
for (final Discoverer discoverer : _discoverers) { for (final Discoverer discoverer : _discoverers) {
@ -872,7 +861,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
return null; return null;
} }
HostVO host = null; HostVO host;
if (deferAgentCreation) { if (deferAgentCreation) {
host = (HostVO)createHostAndAgentDeferred(resource, entry.getValue(), true, hostTags, false); host = (HostVO)createHostAndAgentDeferred(resource, entry.getValue(), true, hostTags, false);
} else { } else {
@ -1099,7 +1088,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
// don't allow to remove the cluster if it has non-removed storage // don't allow to remove the cluster if it has non-removed storage
// pools // pools
final List<StoragePoolVO> storagePools = _storagePoolDao.listPoolsByCluster(cmd.getId()); final List<StoragePoolVO> storagePools = _storagePoolDao.listPoolsByCluster(cmd.getId());
if (storagePools.size() > 0) { if (!storagePools.isEmpty()) {
logger.debug("{} still has storage pools, can't remove", cluster); logger.debug("{} still has storage pools, can't remove", cluster);
throw new CloudRuntimeException(String.format("Cluster: %s cannot be removed. Cluster still has storage pools", cluster)); throw new CloudRuntimeException(String.format("Cluster: %s cannot be removed. Cluster still has storage pools", cluster));
} }
@ -1166,7 +1155,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
} }
} }
Cluster.ClusterType newClusterType = null; Cluster.ClusterType newClusterType;
if (clusterType != null && !clusterType.isEmpty()) { if (clusterType != null && !clusterType.isEmpty()) {
try { try {
newClusterType = Cluster.ClusterType.valueOf(clusterType); newClusterType = Cluster.ClusterType.valueOf(clusterType);
@ -1182,7 +1171,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
} }
} }
Grouping.AllocationState newAllocationState = null; Grouping.AllocationState newAllocationState;
if (allocationState != null && !allocationState.isEmpty()) { if (allocationState != null && !allocationState.isEmpty()) {
try { try {
newAllocationState = Grouping.AllocationState.valueOf(allocationState); newAllocationState = Grouping.AllocationState.valueOf(allocationState);
@ -1244,12 +1233,13 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
} }
} }
final int retry = 40; final int retry = 40;
boolean lsuccess = true; boolean lsuccess;
for (int i = 0; i < retry; i++) { for (int i = 0; i < retry; i++) {
lsuccess = true; lsuccess = true;
try { try {
Thread.sleep(5 * 1000); Thread.currentThread().wait(5 * 1000);
} catch (final Exception e) { } catch (final InterruptedException e) {
logger.debug("thread unexpectedly interrupted during wait, while updating cluster");
} }
hosts = listAllUpAndEnabledHosts(Host.Type.Routing, cluster.getId(), cluster.getPodId(), cluster.getDataCenterId()); hosts = listAllUpAndEnabledHosts(Host.Type.Routing, cluster.getId(), cluster.getPodId(), cluster.getDataCenterId());
for (final HostVO host : hosts) { for (final HostVO host : hosts) {
@ -1258,12 +1248,12 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
break; break;
} }
} }
if (lsuccess == true) { if (lsuccess) {
success = true; success = true;
break; break;
} }
} }
if (success == false) { if (!success) {
throw new CloudRuntimeException("PrepareUnmanaged Failed due to some hosts are still in UP status after 5 Minutes, please try later "); throw new CloudRuntimeException("PrepareUnmanaged Failed due to some hosts are still in UP status after 5 Minutes, please try later ");
} }
} finally { } finally {
@ -1384,7 +1374,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
/* TODO: move below to listener */ /* TODO: move below to listener */
if (host.getType() == Host.Type.Routing) { if (host.getType() == Host.Type.Routing) {
if (vms.size() == 0) { if (vms.isEmpty()) {
return true; return true;
} }
@ -1412,7 +1402,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
String logMessage = String.format( String logMessage = String.format(
"Unsupported host.maintenance.local.storage.strategy: %s. Please set a strategy according to the global settings description: " "Unsupported host.maintenance.local.storage.strategy: %s. Please set a strategy according to the global settings description: "
+ "'Error', 'Migration', or 'ForceStop'.", + "'Error', 'Migration', or 'ForceStop'.",
HOST_MAINTENANCE_LOCAL_STRATEGY.value().toString()); HOST_MAINTENANCE_LOCAL_STRATEGY.value());
logger.error(logMessage); logger.error(logMessage);
throw new CloudRuntimeException("There are active VMs using the host's local storage pool. Please stop all VMs on this host that use local storage."); throw new CloudRuntimeException("There are active VMs using the host's local storage pool. Please stop all VMs on this host that use local storage.");
} }
@ -1469,14 +1459,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
ServiceOfferingVO offeringVO = serviceOfferingDao.findById(vm.getServiceOfferingId()); ServiceOfferingVO offeringVO = serviceOfferingDao.findById(vm.getServiceOfferingId());
final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm, null, offeringVO, null, null); final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm, null, offeringVO, null, null);
plan.setMigrationPlan(true); plan.setMigrationPlan(true);
DeployDestination dest = null; DeployDestination dest = getDeployDestination(vm, profile, plan, host);
DeploymentPlanner.ExcludeList avoids = new DeploymentPlanner.ExcludeList();
avoids.addHost(host.getId());
try {
dest = deploymentManager.planDeployment(profile, plan, avoids, null);
} catch (InsufficientServerCapacityException e) {
throw new CloudRuntimeException(String.format("Maintenance failed, could not find deployment destination for VM: %s.", vm), e);
}
Host destHost = dest.getHost(); Host destHost = dest.getHost();
try { try {
@ -1487,6 +1470,22 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
} }
} }
private DeployDestination getDeployDestination(VMInstanceVO vm, VirtualMachineProfile profile, DataCenterDeployment plan, HostVO hostToAvoid) {
DeployDestination dest;
DeploymentPlanner.ExcludeList avoids = new DeploymentPlanner.ExcludeList();
avoids.addHost(hostToAvoid.getId());
try {
dest = deploymentManager.planDeployment(profile, plan, avoids, null);
} catch (InsufficientServerCapacityException e) {
throw new CloudRuntimeException(String.format("Maintenance failed, could not find deployment destination for VM [id=%s, name=%s].", vm.getId(), vm.getInstanceName()),
e);
}
if (dest == null) {
throw new CloudRuntimeException(String.format("Maintenance failed, could not find deployment destination for VM [id=%s, name=%s], using plan: %s.", vm.getId(), vm.getInstanceName(), plan));
}
return dest;
}
@Override @Override
public boolean maintain(final long hostId) throws AgentUnavailableException { public boolean maintain(final long hostId) throws AgentUnavailableException {
final Boolean result = propagateResourceEvent(hostId, ResourceState.Event.AdminAskMaintenance); final Boolean result = propagateResourceEvent(hostId, ResourceState.Event.AdminAskMaintenance);
@ -1535,15 +1534,15 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
List<VMInstanceVO> migratingInVMs = _vmDao.findByHostInStates(hostId, State.Migrating); List<VMInstanceVO> migratingInVMs = _vmDao.findByHostInStates(hostId, State.Migrating);
if (migratingInVMs.size() > 0) { if (!migratingInVMs.isEmpty()) {
throw new CloudRuntimeException("Host contains incoming VMs migrating. Please wait for them to complete before putting to maintenance."); throw new CloudRuntimeException("Host contains incoming VMs migrating. Please wait for them to complete before putting to maintenance.");
} }
if (_vmDao.findByHostInStates(hostId, State.Starting, State.Stopping).size() > 0) { if (!_vmDao.findByHostInStates(hostId, State.Starting, State.Stopping).isEmpty()) {
throw new CloudRuntimeException("Host contains VMs in starting/stopping state. Please wait for them to complete before putting to maintenance."); throw new CloudRuntimeException("Host contains VMs in starting/stopping state. Please wait for them to complete before putting to maintenance.");
} }
if (_vmDao.findByHostInStates(hostId, State.Error, State.Unknown).size() > 0) { if (!_vmDao.findByHostInStates(hostId, State.Error, State.Unknown).isEmpty()) {
throw new CloudRuntimeException("Host contains VMs in error/unknown/shutdown state. Please fix errors to proceed."); throw new CloudRuntimeException("Host contains VMs in error/unknown/shutdown state. Please fix errors to proceed.");
} }
@ -1564,25 +1563,22 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
if(StringUtils.isBlank(HOST_MAINTENANCE_LOCAL_STRATEGY.value())) { if(StringUtils.isBlank(HOST_MAINTENANCE_LOCAL_STRATEGY.value())) {
return false; return false;
} }
return HOST_MAINTENANCE_LOCAL_STRATEGY.value().toLowerCase().equals(WorkType.Migration.toString().toLowerCase()); return HOST_MAINTENANCE_LOCAL_STRATEGY.value().equalsIgnoreCase(WorkType.Migration.toString());
} }
protected boolean isMaintenanceLocalStrategyForceStop() { protected boolean isMaintenanceLocalStrategyForceStop() {
if(StringUtils.isBlank(HOST_MAINTENANCE_LOCAL_STRATEGY.value())) { if(StringUtils.isBlank(HOST_MAINTENANCE_LOCAL_STRATEGY.value())) {
return false; return false;
} }
return HOST_MAINTENANCE_LOCAL_STRATEGY.value().toLowerCase().equals(WorkType.ForceStop.toString().toLowerCase()); return HOST_MAINTENANCE_LOCAL_STRATEGY.value().equalsIgnoreCase(WorkType.ForceStop.toString());
} }
/** /**
* Returns true if the host.maintenance.local.storage.strategy is the Default: "Error", blank, empty, or null. * Returns true if the host.maintenance.local.storage.strategy is the Default: "Error", blank, empty, or null.
*/ */
protected boolean isMaintenanceLocalStrategyDefault() { protected boolean isMaintenanceLocalStrategyDefault() {
if (StringUtils.isBlank(HOST_MAINTENANCE_LOCAL_STRATEGY.value().toString()) return StringUtils.isBlank(HOST_MAINTENANCE_LOCAL_STRATEGY.value())
|| HOST_MAINTENANCE_LOCAL_STRATEGY.value().toLowerCase().equals(State.Error.toString().toLowerCase())) { || HOST_MAINTENANCE_LOCAL_STRATEGY.value().equalsIgnoreCase(State.Error.toString());
return true;
}
return false;
} }
/** /**
@ -1733,7 +1729,6 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
* Return true if host goes into Maintenance mode. There are various possibilities for VMs' states * Return true if host goes into Maintenance mode. There are various possibilities for VMs' states
* on a host. We need to track the various VM states on each run and accordingly transit to the * on a host. We need to track the various VM states on each run and accordingly transit to the
* appropriate state. * appropriate state.
*
* We change states as follows - * We change states as follows -
* 1. If there are no VMs in running, migrating, starting, stopping, error, unknown states we can move * 1. If there are no VMs in running, migrating, starting, stopping, error, unknown states we can move
* to maintenance state. Note that there cannot be incoming migrations as the API Call prepare for * to maintenance state. Note that there cannot be incoming migrations as the API Call prepare for
@ -1907,7 +1902,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
guestOSDetail.setValue(String.valueOf(guestOSCategory.getId())); guestOSDetail.setValue(String.valueOf(guestOSCategory.getId()));
_hostDetailsDao.update(guestOSDetail.getId(), guestOSDetail); _hostDetailsDao.update(guestOSDetail.getId(), guestOSDetail);
} else { } else {
final Map<String, String> detail = new HashMap<String, String>(); final Map<String, String> detail = new HashMap<>();
detail.put("guest.os.category.id", String.valueOf(guestOSCategory.getId())); detail.put("guest.os.category.id", String.valueOf(guestOSCategory.getId()));
_hostDetailsDao.persist(hostId, detail); _hostDetailsDao.persist(hostId, detail);
} }
@ -2057,9 +2052,9 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
@Override @Override
public List<HypervisorType> getSupportedHypervisorTypes(final long zoneId, final boolean forVirtualRouter, final Long podId) { public List<HypervisorType> getSupportedHypervisorTypes(final long zoneId, final boolean forVirtualRouter, final Long podId) {
final List<HypervisorType> hypervisorTypes = new ArrayList<HypervisorType>(); final List<HypervisorType> hypervisorTypes = new ArrayList<>();
List<ClusterVO> clustersForZone = new ArrayList<ClusterVO>(); List<ClusterVO> clustersForZone;
if (podId != null) { if (podId != null) {
clustersForZone = _clusterDao.listByPodId(podId); clustersForZone = _clusterDao.listByPodId(podId);
} else { } else {
@ -2068,7 +2063,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
for (final ClusterVO cluster : clustersForZone) { for (final ClusterVO cluster : clustersForZone) {
final HypervisorType hType = cluster.getHypervisorType(); final HypervisorType hType = cluster.getHypervisorType();
if (!forVirtualRouter || forVirtualRouter && hType != HypervisorType.BareMetal && hType != HypervisorType.Ovm) { if (!forVirtualRouter || (hType != HypervisorType.BareMetal && hType != HypervisorType.Ovm)) {
hypervisorTypes.add(hType); hypervisorTypes.add(hType);
} }
} }
@ -2104,7 +2099,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
if (isValid) { if (isValid) {
final List<ClusterVO> clusters = _clusterDao.listByDcHyType(zoneId, defaultHyper.toString()); final List<ClusterVO> clusters = _clusterDao.listByDcHyType(zoneId, defaultHyper.toString());
if (clusters.size() <= 0) { if (clusters.isEmpty()) {
isValid = false; isValid = false;
} }
} }
@ -2121,7 +2116,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
HypervisorType defaultHype = getDefaultHypervisor(zoneId); HypervisorType defaultHype = getDefaultHypervisor(zoneId);
if (defaultHype == HypervisorType.None) { if (defaultHype == HypervisorType.None) {
final List<HypervisorType> supportedHypes = getSupportedHypervisorTypes(zoneId, false, null); final List<HypervisorType> supportedHypes = getSupportedHypervisorTypes(zoneId, false, null);
if (supportedHypes.size() > 0) { if (!supportedHypes.isEmpty()) {
Collections.shuffle(supportedHypes); Collections.shuffle(supportedHypes);
defaultHype = supportedHypes.get(0); defaultHype = supportedHypes.get(0);
} }
@ -2245,10 +2240,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
final String cidrNetmask = NetUtils.getCidrSubNet("255.255.255.255", cidrSize); final String cidrNetmask = NetUtils.getCidrSubNet("255.255.255.255", cidrSize);
final long cidrNetmaskNumeric = NetUtils.ip2Long(cidrNetmask); final long cidrNetmaskNumeric = NetUtils.ip2Long(cidrNetmask);
final long serverNetmaskNumeric = NetUtils.ip2Long(serverPrivateNetmask); final long serverNetmaskNumeric = NetUtils.ip2Long(serverPrivateNetmask);
if (serverNetmaskNumeric > cidrNetmaskNumeric) { return serverNetmaskNumeric <= cidrNetmaskNumeric;
return false;
}
return true;
} }
private HostVO getNewHost(StartupCommand[] startupCommands) { private HostVO getNewHost(StartupCommand[] startupCommands) {
@ -2262,11 +2254,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
host = findHostByGuid(startupCommand.getGuidWithoutResource()); host = findHostByGuid(startupCommand.getGuidWithoutResource());
if (host != null) { return host; // even when host == null!
return host;
}
return null;
} }
protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource resource, final Map<String, String> details, List<String> hostTags, protected HostVO createHostVO(final StartupCommand[] cmds, final ServerResource resource, final Map<String, String> details, List<String> hostTags,
@ -2297,11 +2285,11 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
} }
} }
long dcId = -1; long dcId;
DataCenterVO dc = _dcDao.findByName(dataCenter); DataCenterVO dc = _dcDao.findByName(dataCenter);
if (dc == null) { if (dc == null) {
try { try {
dcId = Long.parseLong(dataCenter); dcId = Long.parseLong(dataCenter != null ? dataCenter : "-1");
dc = _dcDao.findById(dcId); dc = _dcDao.findById(dcId);
} catch (final NumberFormatException e) { } catch (final NumberFormatException e) {
logger.debug("Cannot parse " + dataCenter + " into Long."); logger.debug("Cannot parse " + dataCenter + " into Long.");
@ -2315,7 +2303,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
HostPodVO p = _podDao.findByName(pod, dcId); HostPodVO p = _podDao.findByName(pod, dcId);
if (p == null) { if (p == null) {
try { try {
final long podId = Long.parseLong(pod); final long podId = Long.parseLong(pod != null ? pod : "-1");
p = _podDao.findById(podId); p = _podDao.findById(podId);
} catch (final NumberFormatException e) { } catch (final NumberFormatException e) {
logger.debug("Cannot parse " + pod + " into Long."); logger.debug("Cannot parse " + pod + " into Long.");
@ -2334,9 +2322,9 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
clusterId = Long.valueOf(cluster); clusterId = Long.valueOf(cluster);
} catch (final NumberFormatException e) { } catch (final NumberFormatException e) {
if (podId != null) { if (podId != null) {
ClusterVO c = _clusterDao.findBy(cluster, podId.longValue()); ClusterVO c = _clusterDao.findBy(cluster, podId);
if (c == null) { if (c == null) {
c = new ClusterVO(dcId, podId.longValue(), cluster); c = new ClusterVO(dcId, podId, cluster);
c = _clusterDao.persist(c); c = _clusterDao.persist(c);
} }
clusterId = c.getId(); clusterId = c.getId();
@ -2439,7 +2427,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
for (Long hostId : hostIds) { for (Long hostId : hostIds) {
DetailVO hostDetailVO = _hostDetailsDao.findDetail(hostId, name); DetailVO hostDetailVO = _hostDetailsDao.findDetail(hostId, name);
if (hostDetailVO == null || Boolean.parseBoolean(hostDetailVO.getValue()) == false) { if (hostDetailVO == null || !Boolean.parseBoolean(hostDetailVO.getValue())) {
clusterSupportsResigning = false; clusterSupportsResigning = false;
break; break;
@ -2527,7 +2515,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
} }
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
new Request(-1l, -1l, cmds, true, false).logD("Startup request from directly connected host: ", true); new Request(-1L, -1L, cmds, true, false).logD("Startup request from directly connected host: ", true);
} }
if (old) { if (old) {
@ -2597,7 +2585,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
} }
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
new Request(-1l, -1l, cmds, true, false).logD("Startup request from directly connected host: ", true); new Request(-1L, -1L, cmds, true, false).logD("Startup request from directly connected host: ", true);
} }
if (old) { if (old) {
@ -2682,8 +2670,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
@Override @Override
public Host createHostAndAgent(final Long hostId, final ServerResource resource, final Map<String, String> details, final boolean old, final List<String> hostTags, final boolean forRebalance) { public Host createHostAndAgent(final Long hostId, final ServerResource resource, final Map<String, String> details, final boolean old, final List<String> hostTags, final boolean forRebalance) {
final Host host = createHostAndAgent(resource, details, old, hostTags, forRebalance); return createHostAndAgent(resource, details, old, hostTags, forRebalance);
return host;
} }
@Override @Override
@ -2693,8 +2680,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
throw new InvalidParameterValueException("Can't find zone with id " + zoneId); throw new InvalidParameterValueException("Can't find zone with id " + zoneId);
} }
final Map<String, String> details = hostDetails; final String guid = hostDetails.get("guid");
final String guid = details.get("guid");
final List<HostVO> currentHosts = listAllUpAndEnabledHostsInOneZoneByType(hostType, zoneId); final List<HostVO> currentHosts = listAllUpAndEnabledHostsInOneZoneByType(hostType, zoneId);
for (final HostVO currentHost : currentHosts) { for (final HostVO currentHost : currentHosts) {
if (currentHost.getGuid().equals(guid)) { if (currentHost.getGuid().equals(guid)) {
@ -2710,7 +2696,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
return createHostVO(cmds, null, null, null, ResourceStateAdapter.Event.CREATE_HOST_VO_FOR_CONNECTED); return createHostVO(cmds, null, null, null, ResourceStateAdapter.Event.CREATE_HOST_VO_FOR_CONNECTED);
} }
private void checkIPConflicts(final HostPodVO pod, final DataCenterVO dc, final String serverPrivateIP, final String serverPrivateNetmask, final String serverPublicIP, final String serverPublicNetmask) { private void checkIPConflicts(final HostPodVO pod, final DataCenterVO dc, final String serverPrivateIP, final String serverPublicIP) {
// If the server's private IP is the same as is public IP, this host has // If the server's private IP is the same as is public IP, this host has
// a host-only private network. Don't check for conflicts with the // a host-only private network. Don't check for conflicts with the
// private IP address table. // private IP address table.
@ -2739,7 +2725,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
// If the server's public IP address is already in the database, // If the server's public IP address is already in the database,
// return false // return false
final List<IPAddressVO> existingPublicIPs = _publicIPAddressDao.listByDcIdIpAddress(dc.getId(), serverPublicIP); final List<IPAddressVO> existingPublicIPs = _publicIPAddressDao.listByDcIdIpAddress(dc.getId(), serverPublicIP);
if (existingPublicIPs.size() > 0) { if (!existingPublicIPs.isEmpty()) {
throw new IllegalArgumentException("The public ip address of the server (" + serverPublicIP + ") is already in use in zone: " + dc.getName()); throw new IllegalArgumentException("The public ip address of the server (" + serverPublicIP + ") is already in use in zone: " + dc.getName());
} }
} }
@ -2776,7 +2762,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
final HostPodVO pod = _podDao.findById(host.getPodId()); final HostPodVO pod = _podDao.findById(host.getPodId());
final DataCenterVO dc = _dcDao.findById(host.getDataCenterId()); final DataCenterVO dc = _dcDao.findById(host.getDataCenterId());
checkIPConflicts(pod, dc, ssCmd.getPrivateIpAddress(), ssCmd.getPublicIpAddress(), ssCmd.getPublicIpAddress(), ssCmd.getPublicNetmask()); checkIPConflicts(pod, dc, ssCmd.getPrivateIpAddress(), ssCmd.getPublicIpAddress());
host.setType(com.cloud.host.Host.Type.Routing); host.setType(com.cloud.host.Host.Type.Routing);
host.setDetails(details); host.setDetails(details);
host.setCaps(ssCmd.getCapabilities()); host.setCaps(ssCmd.getCapabilities());
@ -2814,8 +2800,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
throw new UnableDeleteHostException("Failed to set primary storage into maintenance mode"); throw new UnableDeleteHostException("Failed to set primary storage into maintenance mode");
} }
} catch (final Exception e) { } catch (final Exception e) {
logger.debug("Failed to set primary storage into maintenance mode, due to: " + e.toString()); logger.debug("Failed to set primary storage into maintenance mode", e);
throw new UnableDeleteHostException("Failed to set primary storage into maintenance mode, due to: " + e.toString()); throw new UnableDeleteHostException("Failed to set primary storage into maintenance mode, due to: " + e);
} }
} }
@ -2959,7 +2945,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
if (result.getReturnCode() != 0) { if (result.getReturnCode() != 0) {
throw new CloudRuntimeException(String.format("Could not restart agent on %s due to: %s", host, result.getStdErr())); throw new CloudRuntimeException(String.format("Could not restart agent on %s due to: %s", host, result.getStdErr()));
} }
logger.debug("cloudstack-agent restart result: " + result.toString()); logger.debug("cloudstack-agent restart result: {}", result);
} catch (final SshException e) { } catch (final SshException e) {
throw new CloudRuntimeException("SSH to agent is enabled, but agent restart failed", e); throw new CloudRuntimeException("SSH to agent is enabled, but agent restart failed", e);
} }
@ -2980,7 +2966,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
} }
@Override @Override
public boolean executeUserRequest(final long hostId, final ResourceState.Event event) throws AgentUnavailableException { public boolean executeUserRequest(final long hostId, final ResourceState.Event event) {
if (event == ResourceState.Event.AdminAskMaintenance) { if (event == ResourceState.Event.AdminAskMaintenance) {
return doMaintain(hostId); return doMaintain(hostId);
} else if (event == ResourceState.Event.AdminCancelMaintenance) { } else if (event == ResourceState.Event.AdminCancelMaintenance) {
@ -3306,7 +3292,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
public HostStats getHostStatistics(final Host host) { public HostStats getHostStatistics(final Host host) {
final Answer answer = _agentMgr.easySend(host.getId(), new GetHostStatsCommand(host.getGuid(), host.getName(), host.getId())); final Answer answer = _agentMgr.easySend(host.getId(), new GetHostStatsCommand(host.getGuid(), host.getName(), host.getId()));
if (answer != null && answer instanceof UnsupportedAnswer) { if (answer instanceof UnsupportedAnswer) {
return null; return null;
} }
@ -3342,20 +3328,16 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
@Override @Override
public String getHostTags(final long hostId) { public String getHostTags(final long hostId) {
final List<String> hostTags = _hostTagsDao.getHostTags(hostId).parallelStream().map(HostTagVO::getTag).collect(Collectors.toList()); final List<String> hostTags = _hostTagsDao.getHostTags(hostId).parallelStream().map(HostTagVO::getTag).collect(Collectors.toList());
if (hostTags == null) { return StringUtils.listToCsvTags(hostTags);
return null;
} else {
return com.cloud.utils.StringUtils.listToCsvTags(hostTags);
}
} }
@Override @Override
public List<PodCluster> listByDataCenter(final long dcId) { public List<PodCluster> listByDataCenter(final long dcId) {
final List<HostPodVO> pods = _podDao.listByDataCenterId(dcId); final List<HostPodVO> pods = _podDao.listByDataCenterId(dcId);
final ArrayList<PodCluster> pcs = new ArrayList<PodCluster>(); final ArrayList<PodCluster> pcs = new ArrayList<>();
for (final HostPodVO pod : pods) { for (final HostPodVO pod : pods) {
final List<ClusterVO> clusters = _clusterDao.listByPodId(pod.getId()); final List<ClusterVO> clusters = _clusterDao.listByPodId(pod.getId());
if (clusters.size() == 0) { if (clusters.isEmpty()) {
pcs.add(new PodCluster(pod, null)); pcs.add(new PodCluster(pod, null));
} else { } else {
for (final ClusterVO cluster : clusters) { for (final ClusterVO cluster : clusters) {
@ -3400,7 +3382,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
public boolean isHostGpuEnabled(final long hostId) { public boolean isHostGpuEnabled(final long hostId) {
final SearchCriteria<HostGpuGroupsVO> sc = _gpuAvailability.create(); final SearchCriteria<HostGpuGroupsVO> sc = _gpuAvailability.create();
sc.setParameters("hostId", hostId); sc.setParameters("hostId", hostId);
return _hostGpuGroupsDao.customSearch(sc, null).size() > 0 ? true : false; return !_hostGpuGroupsDao.customSearch(sc, null).isEmpty();
} }
@Override @Override
@ -3465,7 +3447,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
// Update GPU group capacity // Update GPU group capacity
final TransactionLegacy txn = TransactionLegacy.currentTxn(); final TransactionLegacy txn = TransactionLegacy.currentTxn();
txn.start(); txn.start();
_hostGpuGroupsDao.persist(hostId, new ArrayList<String>(groupDetails.keySet())); _hostGpuGroupsDao.persist(hostId, new ArrayList<>(groupDetails.keySet()));
_vgpuTypesDao.persist(hostId, groupDetails); _vgpuTypesDao.persist(hostId, groupDetails);
txn.commit(); txn.commit();
} }
@ -3473,7 +3455,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
@Override @Override
public HashMap<String, HashMap<String, VgpuTypesInfo>> getGPUStatistics(final HostVO host) { public HashMap<String, HashMap<String, VgpuTypesInfo>> getGPUStatistics(final HostVO host) {
final Answer answer = _agentMgr.easySend(host.getId(), new GetGPUStatsCommand(host.getGuid(), host.getName())); final Answer answer = _agentMgr.easySend(host.getId(), new GetGPUStatsCommand(host.getGuid(), host.getName()));
if (answer != null && answer instanceof UnsupportedAnswer) { if (answer instanceof UnsupportedAnswer) {
return null; return null;
} }
if (answer == null || !answer.getResult()) { if (answer == null || !answer.getResult()) {
@ -3514,7 +3496,7 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
@ActionEvent(eventType = EventTypes.EVENT_HOST_RESERVATION_RELEASE, eventDescription = "releasing host reservation", async = true) @ActionEvent(eventType = EventTypes.EVENT_HOST_RESERVATION_RELEASE, eventDescription = "releasing host reservation", async = true)
public boolean releaseHostReservation(final Long hostId) { public boolean releaseHostReservation(final Long hostId) {
try { try {
return Transaction.execute(new TransactionCallback<Boolean>() { return Transaction.execute(new TransactionCallback<>() {
@Override @Override
public Boolean doInTransaction(final TransactionStatus status) { public Boolean doInTransaction(final TransactionStatus status) {
final PlannerHostReservationVO reservationEntry = _plannerHostReserveDao.findByHostId(hostId); final PlannerHostReservationVO reservationEntry = _plannerHostReserveDao.findByHostId(hostId);

View File

@ -123,7 +123,7 @@ export default {
dataView: true, dataView: true,
groupAction: true, groupAction: true,
popup: true, popup: true,
groupMap: (selection, values) => { return selection.map(x => { return { id: x, considerlasthost: values.considerlasthost } }) }, groupMap: (selection, values) => { return selection.map(x => { return { id: x, considerlasthost: values.considerlasthost === true } }) },
args: (record, store) => { args: (record, store) => {
if (['Admin'].includes(store.userInfo.roletype)) { if (['Admin'].includes(store.userInfo.roletype)) {
return ['considerlasthost'] return ['considerlasthost']

View File

@ -115,9 +115,14 @@ export default {
label: 'label.disable.host', label: 'label.disable.host',
message: 'message.confirm.disable.host', message: 'message.confirm.disable.host',
dataView: true, dataView: true,
show: (record) => { return record.resourcestate === 'Enabled' }, show: (record) => record.resourcestate === 'Enabled',
popup: true, popup: true,
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/HostEnableDisable'))) component: shallowRef(defineAsyncComponent(() => import('@/views/infra/HostEnableDisable'))),
events: {
'refresh-data': () => {
store.dispatch('refreshCurrentPage')
}
}
}, },
{ {
api: 'updateHost', api: 'updateHost',
@ -125,9 +130,14 @@ export default {
label: 'label.enable.host', label: 'label.enable.host',
message: 'message.confirm.enable.host', message: 'message.confirm.enable.host',
dataView: true, dataView: true,
show: (record) => { return record.resourcestate === 'Disabled' }, show: (record) => record.resourcestate === 'Disabled',
popup: true, popup: true,
component: shallowRef(defineAsyncComponent(() => import('@/views/infra/HostEnableDisable'))) component: shallowRef(defineAsyncComponent(() => import('@/views/infra/HostEnableDisable'))),
events: {
'refresh-data': () => {
store.dispatch('refreshCurrentPage')
}
}
}, },
{ {
api: 'prepareHostForMaintenance', api: 'prepareHostForMaintenance',

View File

@ -243,7 +243,7 @@ export default {
id: this.resource.id id: this.resource.id
} }
for (const key in values) { for (const key in values) {
if (values[key]) { if (values[key] || values[key] === false) {
params[key] = values[key] params[key] = values[key]
} }
} }

View File

@ -18,7 +18,7 @@
<template> <template>
<div class="form-layout"> <div class="form-layout">
<a-form <a-form
:ref="formRef" ref="formRef"
:model="form" :model="form"
:rules="rules" :rules="rules"
@finish="handleSubmit" @finish="handleSubmit"
@ -54,7 +54,7 @@
</template> </template>
<script> <script>
import { ref, reactive, toRaw } from 'vue' import { reactive, toRaw } from 'vue'
import { api } from '@/api' import { api } from '@/api'
export default { export default {
@ -78,11 +78,8 @@ export default {
this.resourcestate = this.resource.resourcestate this.resourcestate = this.resource.resourcestate
this.allocationstate = this.resourcestate === 'Enabled' ? 'Disable' : 'Enable' this.allocationstate = this.resourcestate === 'Enabled' ? 'Disable' : 'Enable'
}, },
beforeCreate () {
},
methods: { methods: {
initForm () { initForm () {
this.formRef = ref()
this.form = reactive({}) this.form = reactive({})
this.rules = reactive({}) this.rules = reactive({})
}, },
@ -97,11 +94,9 @@ export default {
}) })
}, },
handleSubmit (e) { handleSubmit (e) {
e.preventDefault() this.$refs.formRef.validate().then(() => {
this.formRef.value.validate().then(() => {
const values = toRaw(this.form) const values = toRaw(this.form)
const data = {
var data = {
allocationstate: this.allocationstate, allocationstate: this.allocationstate,
id: this.resource.id id: this.resource.id
} }
@ -110,24 +105,27 @@ export default {
} }
api('updateHost', data).then(_ => { api('updateHost', data).then(_ => {
this.$emit('close-action') this.$emit('close-action')
this.$emit('refresh-data')
}).catch(err => {
this.$message.error(err.message || 'Failed to update host status')
}) })
}).catch(() => {
this.$message.error('Validation failed. Please check the inputs.')
}) })
} }
} }
} }
</script> </script>
<style scoped> <style scoped>
.reason { .reason {
padding-top: 20px padding-top: 20px;
} }
.form-layout { .form-layout {
width: 30vw; width: 30vw;
@media (min-width: 500px) {
@media (min-width: 500px) { width: 450px;
width: 450px;
}
} }
}
</style> </style>

View File

@ -625,9 +625,9 @@ export default {
if (this.publicLBExists && (idx === -1 || this.lbProviderMap.publicLb.vpc.indexOf(offering.service.map(svc => { return svc.provider[0].name })[idx]) === -1)) { if (this.publicLBExists && (idx === -1 || this.lbProviderMap.publicLb.vpc.indexOf(offering.service.map(svc => { return svc.provider[0].name })[idx]) === -1)) {
filteredOfferings.push(offering) filteredOfferings.push(offering)
} else if (!this.publicLBExists && vpcLbServiceIndex > -1) { } else if (!this.publicLBExists && vpcLbServiceIndex > -1) {
const vpcLbServiceProvider = vpcLbServiceIndex === -1 ? undefined : this.resource.service[vpcLbServiceIndex].provider[0].name const vpcLbServiceProviders = vpcLbServiceIndex === -1 ? undefined : this.resource.service[vpcLbServiceIndex].provider.map(provider => provider.name)
const offeringLbServiceProvider = idx === -1 ? undefined : offering.service[idx].provider[0].name const offeringLbServiceProvider = idx === -1 ? undefined : offering.service[idx].provider[0].name
if (vpcLbServiceProvider && (!offeringLbServiceProvider || (offeringLbServiceProvider && vpcLbServiceProvider === offeringLbServiceProvider))) { if (vpcLbServiceProviders && (!offeringLbServiceProvider || (offeringLbServiceProvider && vpcLbServiceProviders.includes(offeringLbServiceProvider)))) {
filteredOfferings.push(offering) filteredOfferings.push(offering)
} }
} else { } else {