Merge branch '4.20'

This commit is contained in:
Daan Hoogland 2025-03-27 17:03:13 +01:00
commit 8af021c6f6
34 changed files with 589 additions and 227 deletions

View File

@ -20,6 +20,19 @@ import os
import logging import logging
import sys import sys
import socket import socket
# ---- This snippet of code adds the sources path and the waf configured PYTHONDIR to the Python path ----
# ---- We do this so cloud_utils can be looked up in the following order:
# ---- 1) Sources directory
# ---- 2) waf configured PYTHONDIR
# ---- 3) System Python path
for pythonpath in (
"@PYTHONDIR@",
os.path.join(os.path.dirname(__file__),os.path.pardir,os.path.pardir,"python","lib"),
):
if os.path.isdir(pythonpath): sys.path.insert(0,pythonpath)
# ---- End snippet of code ----
from cloudutils.cloudException import CloudRuntimeException, CloudInternalException from cloudutils.cloudException import CloudRuntimeException, CloudInternalException
from cloudutils.utilities import initLoging, bash from cloudutils.utilities import initLoging, bash
from cloudutils.configFileOps import configFileOps from cloudutils.configFileOps import configFileOps

View File

@ -20,6 +20,19 @@ import sys
import os import os
import subprocess import subprocess
from threading import Timer from threading import Timer
# ---- This snippet of code adds the sources path and the waf configured PYTHONDIR to the Python path ----
# ---- We do this so cloud_utils can be looked up in the following order:
# ---- 1) Sources directory
# ---- 2) waf configured PYTHONDIR
# ---- 3) System Python path
for pythonpath in (
"@PYTHONDIR@",
os.path.join(os.path.dirname(__file__),os.path.pardir,os.path.pardir,"python","lib"),
):
if os.path.isdir(pythonpath): sys.path.insert(0,pythonpath)
# ---- End snippet of code ----
from xml.dom.minidom import parse from xml.dom.minidom import parse
from cloudutils.configFileOps import configFileOps from cloudutils.configFileOps import configFileOps
from cloudutils.networkConfig import networkConfig from cloudutils.networkConfig import networkConfig

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

@ -16,13 +16,27 @@
# specific language governing permissions and limitations # specific language governing permissions and limitations
# under the License. # under the License.
import os
import sys import sys
# ---- This snippet of code adds the sources path and the waf configured PYTHONDIR to the Python path ----
# ---- We do this so cloud_utils can be looked up in the following order:
# ---- 1) Sources directory
# ---- 2) waf configured PYTHONDIR
# ---- 3) System Python path
for pythonpath in (
"@PYTHONDIR@",
os.path.join(os.path.dirname(__file__),os.path.pardir,os.path.pardir,"python","lib"),
):
if os.path.isdir(pythonpath): sys.path.insert(0,pythonpath)
# ---- End snippet of code ----
from cloudutils.syscfg import sysConfigFactory from cloudutils.syscfg import sysConfigFactory
from cloudutils.utilities import initLoging, UnknownSystemException from cloudutils.utilities import initLoging, UnknownSystemException
from cloudutils.cloudException import CloudRuntimeException, CloudInternalException from cloudutils.cloudException import CloudRuntimeException, CloudInternalException
from cloudutils.globalEnv import globalEnv from cloudutils.globalEnv import globalEnv
from cloudutils.serviceConfigServer import cloudManagementConfig from cloudutils.serviceConfigServer import cloudManagementConfig
from optparse import OptionParser from optparse import OptionParser
if __name__ == '__main__': if __name__ == '__main__':
initLoging("@MSLOGDIR@/setupManagement.log") initLoging("@MSLOGDIR@/setupManagement.log")
glbEnv = globalEnv() glbEnv = globalEnv()

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

@ -85,7 +85,7 @@ public class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin {
List<ScopedConfigStorage> _scopedStorages; List<ScopedConfigStorage> _scopedStorages;
Set<Configurable> _configured = Collections.synchronizedSet(new HashSet<Configurable>()); Set<Configurable> _configured = Collections.synchronizedSet(new HashSet<Configurable>());
Set<String> newConfigs = Collections.synchronizedSet(new HashSet<>()); Set<String> newConfigs = Collections.synchronizedSet(new HashSet<>());
LazyCache<String, String> configCache; LazyCache<Ternary<String, ConfigKey.Scope, Long>, String> configCache;
private HashMap<String, Pair<String, ConfigKey<?>>> _allKeys = new HashMap<String, Pair<String, ConfigKey<?>>>(1007); private HashMap<String, Pair<String, ConfigKey<?>>> _allKeys = new HashMap<String, Pair<String, ConfigKey<?>>>(1007);
@ -275,15 +275,10 @@ public class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin {
return _configDao; return _configDao;
} }
protected String getConfigStringValueInternal(String cacheKey) { protected String getConfigStringValueInternal(Ternary<String, ConfigKey.Scope, Long> cacheKey) {
String[] parts = cacheKey.split("-"); String key = cacheKey.first();
String key = parts[0]; ConfigKey.Scope scope = cacheKey.second();
ConfigKey.Scope scope = ConfigKey.Scope.Global; Long scopeId = cacheKey.third();
Long scopeId = null;
try {
scope = ConfigKey.Scope.valueOf(parts[1]);
scopeId = Long.valueOf(parts[2]);
} catch (IllegalArgumentException ignored) {}
if (!ConfigKey.Scope.Global.equals(scope) && scopeId != null) { if (!ConfigKey.Scope.Global.equals(scope) && scopeId != null) {
ScopedConfigStorage scopedConfigStorage = getScopedStorage(scope); ScopedConfigStorage scopedConfigStorage = getScopedStorage(scope);
if (scopedConfigStorage == null) { if (scopedConfigStorage == null) {
@ -298,8 +293,8 @@ public class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin {
return null; return null;
} }
private String getConfigCacheKey(String key, ConfigKey.Scope scope, Long scopeId) { protected Ternary<String, ConfigKey.Scope, Long> getConfigCacheKey(String key, ConfigKey.Scope scope, Long scopeId) {
return String.format("%s-%s-%d", key, scope, (scopeId == null ? 0 : scopeId)); return new Ternary<>(key, scope, scopeId);
} }
@Override @Override

View File

@ -89,6 +89,12 @@ public class ConfigDepotImplTest {
runTestGetConfigStringValue("test", "value"); runTestGetConfigStringValue("test", "value");
} }
@Test
public void testGetConfigStringValue_nameWithCharacters() {
runTestGetConfigStringValue("test.1-1", "value");
runTestGetConfigStringValue("test_1#2", "value");
}
private void runTestGetConfigStringValueExpiry(long wait, int configDBRetrieval) { private void runTestGetConfigStringValueExpiry(long wait, int configDBRetrieval) {
String key = "test1"; String key = "test1";
String value = "expiry"; String value = "expiry";

View File

@ -49,8 +49,12 @@ public class GenericPresetVariable {
fieldNamesToIncludeInToString.add("name"); fieldNamesToIncludeInToString.add("name");
} }
/***
* Converts the preset variable into a valid JSON object that will be injected into the JS interpreter.
* This method should not be overridden or changed.
*/
@Override @Override
public String toString() { public final String toString() {
return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, fieldNamesToIncludeInToString.toArray(new String[0])); return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, fieldNamesToIncludeInToString.toArray(new String[0]));
} }
} }

View File

@ -40,8 +40,12 @@ public class Resource {
this.domainId = domainId; this.domainId = domainId;
} }
/***
* Converts the preset variable into a valid JSON object that will be injected into the JS interpreter.
* This method should not be overridden or changed.
*/
@Override @Override
public String toString() { public final String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE); return ToStringBuilder.reflectionToString(this, ToStringStyle.JSON_STYLE);
} }

View File

@ -189,13 +189,6 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
super(); super();
} }
private Double findRatioValue(final String value) {
if (value != null) {
return Double.valueOf(value);
}
return 1.0;
}
private void updateHostMetrics(final HostMetrics hostMetrics, final HostJoinVO host) { private void updateHostMetrics(final HostMetrics hostMetrics, final HostJoinVO host) {
hostMetrics.addCpuAllocated(host.getCpuReservedCapacity() + host.getCpuUsedCapacity()); hostMetrics.addCpuAllocated(host.getCpuReservedCapacity() + host.getCpuUsedCapacity());
hostMetrics.addMemoryAllocated(host.getMemReservedCapacity() + host.getMemUsedCapacity()); hostMetrics.addMemoryAllocated(host.getMemReservedCapacity() + host.getMemUsedCapacity());
@ -767,14 +760,10 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
if (AllowListMetricsComputation.value()) { if (AllowListMetricsComputation.value()) {
List<Ternary<Long, Long, Long>> cpuList = new ArrayList<>(); List<Ternary<Long, Long, Long>> cpuList = new ArrayList<>();
List<Ternary<Long, Long, Long>> memoryList = new ArrayList<>(); List<Ternary<Long, Long, Long>> memoryList = new ArrayList<>();
for (final Host host : hostDao.findByClusterId(clusterId)) { for (final HostJoinVO host : hostJoinDao.findByClusterId(clusterId, Host.Type.Routing)) {
if (host == null || host.getType() != Host.Type.Routing) { updateHostMetrics(hostMetrics, host);
continue; cpuList.add(new Ternary<>(host.getCpuUsedCapacity(), host.getCpuReservedCapacity(), host.getCpus() * host.getSpeed()));
} memoryList.add(new Ternary<>(host.getMemUsedCapacity(), host.getMemReservedCapacity(), host.getTotalMemory()));
updateHostMetrics(hostMetrics, hostJoinDao.findById(host.getId()));
HostJoinVO hostJoin = hostJoinDao.findById(host.getId());
cpuList.add(new Ternary<>(hostJoin.getCpuUsedCapacity(), hostJoin.getCpuReservedCapacity(), hostJoin.getCpus() * hostJoin.getSpeed()));
memoryList.add(new Ternary<>(hostJoin.getMemUsedCapacity(), hostJoin.getMemReservedCapacity(), hostJoin.getTotalMemory()));
} }
try { try {
Double imbalance = ClusterDrsAlgorithm.getClusterImbalance(clusterId, cpuList, memoryList, null); Double imbalance = ClusterDrsAlgorithm.getClusterImbalance(clusterId, cpuList, memoryList, null);
@ -955,11 +944,8 @@ public class MetricsServiceImpl extends MutualExclusiveIdsManagerBase implements
if (cluster == null) { if (cluster == null) {
continue; continue;
} }
for (final Host host: hostDao.findByClusterId(cluster.getId())) { for (final HostJoinVO host: hostJoinDao.findByClusterId(cluster.getId(), Host.Type.Routing)) {
if (host == null || host.getType() != Host.Type.Routing) { updateHostMetrics(hostMetrics, host);
continue;
}
updateHostMetrics(hostMetrics, hostJoinDao.findById(host.getId()));
} }
} }
} else { } else {

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,8 +286,11 @@ public class LinstorPrimaryDataStoreLifeCycleImpl extends BasePrimaryDataStoreLi
@Override @Override
public boolean deleteDataStore(DataStore store) { public boolean deleteDataStore(DataStore store) {
if (cleanupDatastore(store)) {
return dataStoreHelper.deletePrimaryDataStore(store); return dataStoreHelper.deletePrimaryDataStore(store);
} }
return false;
}
/* (non-Javadoc) /* (non-Javadoc)
* @see org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle#migrateToObjectStore(org.apache.cloudstack.engine.subsystem.api.storage.DataStore) * @see org.apache.cloudstack.engine.subsystem.api.storage.DataStoreLifeCycle#migrateToObjectStore(org.apache.cloudstack.engine.subsystem.api.storage.DataStore)

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,38 +312,12 @@ 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());
if (storagePoolVO == null) {
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); ScaleIOGatewayClientConnectionPool.getInstance().removeClient(dataStore);
return dataStoreHelper.deletePrimaryDataStore(dataStore); return dataStoreHelper.deletePrimaryDataStore(dataStore);
} }
return false;
}
@Override @Override
public boolean migrateToObjectStore(DataStore store) { public boolean migrateToObjectStore(DataStore store) {

View File

@ -39,11 +39,11 @@ class sysConfigAgentFactory:
return sysConfigAgentUbuntu(glbEnv) return sysConfigAgentUbuntu(glbEnv)
elif distribution == "CentOS" or distribution == "RHEL5": elif distribution == "CentOS" or distribution == "RHEL5":
return sysConfigEL5(glbEnv) return sysConfigEL5(glbEnv)
elif distribution == "Fedora" or distribution == "RHEL6": elif distribution == "RHEL6":
return sysConfigEL6(glbEnv) return sysConfigEL6(glbEnv)
elif distribution == "RHEL7": elif distribution == "RHEL7":
return sysConfigEL7(glbEnv) return sysConfigEL7(glbEnv)
elif distribution in ["RHEL8", "RHEL9"]: elif distribution in ["Fedora", "RHEL8", "RHEL9", "RHEL10"]:
return sysConfigEL(glbEnv) return sysConfigEL(glbEnv)
elif distribution == "SUSE": elif distribution == "SUSE":
return sysConfigSUSE(glbEnv) return sysConfigSUSE(glbEnv)
@ -183,9 +183,10 @@ class sysConfigEL5(sysConfigAgentRedhatBase):
networkConfigRedhat(self), networkConfigRedhat(self),
libvirtConfigRedhat(self), libvirtConfigRedhat(self),
firewallConfigAgent(self), firewallConfigAgent(self),
nfsConfig(self),
cloudAgentConfig(self)] cloudAgentConfig(self)]
#it covers RHEL6/Fedora13/Fedora14 #it covers RHEL6
class sysConfigEL6(sysConfigAgentRedhatBase): class sysConfigEL6(sysConfigAgentRedhatBase):
def __init__(self, glbEnv): def __init__(self, glbEnv):
super(sysConfigEL6, self).__init__(glbEnv) super(sysConfigEL6, self).__init__(glbEnv)

View File

@ -124,6 +124,10 @@ class Distribution:
version.find("Red Hat Enterprise Linux release 9") != -1 or version.find("Linux release 9.") != -1 or version.find("Red Hat Enterprise Linux release 9") != -1 or version.find("Linux release 9.") != -1 or
version.find("Linux release 9") != -1): version.find("Linux release 9") != -1):
self.distro = "RHEL9" self.distro = "RHEL9"
elif (version.find("Red Hat Enterprise Linux Server release 10") != -1 or version.find("Scientific Linux release 10") != -1 or
version.find("Red Hat Enterprise Linux release 10") != -1 or version.find("Linux release 10.") != -1 or
version.find("Linux release 10") != -1):
self.distro = "RHEL10"
elif version.find("CentOS") != -1: elif version.find("CentOS") != -1:
self.distro = "CentOS" self.distro = "CentOS"
else: else:

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();
if (routerToBeAvoid.getPodIdToDeployIn() != null) {
avoids[0].addPod(routerToBeAvoid.getPodIdToDeployIn()); 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;
@ -2531,7 +2519,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) {
@ -2601,7 +2589,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) {
@ -2702,8 +2690,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)) {
@ -2719,7 +2706,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.
@ -2748,7 +2735,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());
} }
} }
@ -2785,7 +2772,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());
@ -2823,8 +2810,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);
} }
} }
@ -2968,7 +2955,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);
} }
@ -2989,7 +2976,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) {
@ -3315,7 +3302,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;
} }
@ -3351,20 +3338,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) {
@ -3409,7 +3392,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
@ -3474,7 +3457,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();
} }
@ -3482,7 +3465,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()) {
@ -3523,7 +3506,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

@ -16,7 +16,7 @@
// under the License. // under the License.
package org.apache.cloudstack.storage.heuristics.presetvariables; package org.apache.cloudstack.storage.heuristics.presetvariables;
public class Domain extends GenericHeuristicPresetVariable{ public class Domain extends GenericHeuristicPresetVariable {
private String id; private String id;
public String getId() { public String getId() {

View File

@ -36,10 +36,12 @@ public class GenericHeuristicPresetVariable {
fieldNamesToIncludeInToString.add("name"); fieldNamesToIncludeInToString.add("name");
} }
/***
* Converts the preset variable into a valid JSON object that will be injected into the JS interpreter.
* This method should not be overridden or changed.
*/
@Override @Override
public String toString() { public final String toString() {
return String.format("GenericHeuristicPresetVariable %s", return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, fieldNamesToIncludeInToString.toArray(new String[0]));
ReflectionToStringBuilderUtils.reflectOnlySelectedFields(
this, fieldNamesToIncludeInToString.toArray(new String[0])));
} }
} }

View File

@ -0,0 +1,46 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.storage.heuristics.presetvariables;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class AccountTest {
@Test
public void toStringTestReturnsValidJson() {
Account variable = new Account();
variable.setName("test name");
variable.setId("test id");
Domain domainVariable = new Domain();
domainVariable.setId("domain id");
domainVariable.setName("domain name");
variable.setDomain(domainVariable);
String expected = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(variable, "name", "id", "domain");
String result = variable.toString();
Assert.assertEquals(expected, result);
}
}

View File

@ -0,0 +1,41 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.storage.heuristics.presetvariables;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class DomainTest {
@Test
public void toStringTestReturnsValidJson() {
Domain variable = new Domain();
variable.setName("test name");
variable.setId("test id");
String expected = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(variable, "name", "id");
String result = variable.toString();
Assert.assertEquals(expected, result);
}
}

View File

@ -0,0 +1,40 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.storage.heuristics.presetvariables;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class GenericHeuristicPresetVariableTest {
@Test
public void toStringTestReturnsValidJson() {
GenericHeuristicPresetVariable variable = new GenericHeuristicPresetVariable();
variable.setName("test name");
String expected = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(variable, "name");
String result = variable.toString();
Assert.assertEquals(expected, result);
}
}

View File

@ -0,0 +1,45 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.storage.heuristics.presetvariables;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class SecondaryStorageTest {
@Test
public void toStringTestReturnsValidJson() {
SecondaryStorage variable = new SecondaryStorage();
variable.setName("test name");
variable.setId("test id");
variable.setProtocol("test protocol");
variable.setUsedDiskSize(1L);
variable.setTotalDiskSize(2L);
String expected = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(variable, "name", "id",
"protocol", "usedDiskSize", "totalDiskSize");
String result = variable.toString();
Assert.assertEquals(expected, result);
}
}

View File

@ -0,0 +1,44 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.storage.heuristics.presetvariables;
import com.cloud.hypervisor.Hypervisor;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class SnapshotTest {
@Test
public void toStringTestReturnsValidJson() {
Snapshot variable = new Snapshot();
variable.setName("test name");
variable.setSize(1L);
variable.setHypervisorType(Hypervisor.HypervisorType.KVM);
String expected = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(variable, "name", "size",
"hypervisorType");
String result = variable.toString();
Assert.assertEquals(expected, result);
}
}

View File

@ -0,0 +1,46 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.storage.heuristics.presetvariables;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.Storage;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class TemplateTest {
@Test
public void toStringTestReturnsValidJson() {
Template variable = new Template();
variable.setName("test name");
variable.setTemplateType(Storage.TemplateType.USER);
variable.setHypervisorType(Hypervisor.HypervisorType.KVM);
variable.setFormat(Storage.ImageFormat.QCOW2);
String expected = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(variable, "name", "templateType",
"hypervisorType", "format");
String result = variable.toString();
Assert.assertEquals(expected, result);
}
}

View File

@ -0,0 +1,44 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.storage.heuristics.presetvariables;
import com.cloud.storage.Storage;
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class VolumeTest {
@Test
public void toStringTestReturnsValidJson() {
Volume variable = new Volume();
variable.setName("test name");
variable.setFormat(Storage.ImageFormat.QCOW2);
variable.setSize(1L);
String expected = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(variable, "name", "format",
"size");
String result = variable.toString();
Assert.assertEquals(expected, result);
}
}

View File

@ -1069,7 +1069,7 @@ test_data = {
"format": "raw", "format": "raw",
"hypervisor": "kvm", "hypervisor": "kvm",
"ostype": "Other Linux (64-bit)", "ostype": "Other Linux (64-bit)",
"url": "https://cloud-images.ubuntu.com/releases/22.04/release/ubuntu-22.04-server-cloudimg-amd64.img", "url": "https://cloud-images.ubuntu.com/releases/jammy/release/ubuntu-22.04-server-cloudimg-amd64.img",
"requireshvm": "True", "requireshvm": "True",
"ispublic": "True", "ispublic": "True",
"isextractable": "False" "isextractable": "False"

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

@ -116,9 +116,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',
@ -126,9 +131,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 {