Merge branch '4.19' into 4.20

This commit is contained in:
Daan Hoogland 2025-05-13 11:41:36 +02:00
commit dd84c74e82
8 changed files with 370 additions and 244 deletions

View File

@ -5,6 +5,11 @@ 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-05-07]
### Added
- Implemented storage/volume stats
## [2025-03-13] ## [2025-03-13]
### Fixed ### Fixed

View File

@ -28,11 +28,11 @@ import com.linbit.linstor.api.model.ResourceDefinition;
import com.linbit.linstor.api.model.ResourceDefinitionCloneRequest; import com.linbit.linstor.api.model.ResourceDefinitionCloneRequest;
import com.linbit.linstor.api.model.ResourceDefinitionCloneStarted; import com.linbit.linstor.api.model.ResourceDefinitionCloneStarted;
import com.linbit.linstor.api.model.ResourceDefinitionCreate; import com.linbit.linstor.api.model.ResourceDefinitionCreate;
import com.linbit.linstor.api.model.ResourceDefinitionModify; import com.linbit.linstor.api.model.ResourceDefinitionModify;
import com.linbit.linstor.api.model.ResourceGroup; import com.linbit.linstor.api.model.ResourceGroup;
import com.linbit.linstor.api.model.ResourceGroupSpawn; import com.linbit.linstor.api.model.ResourceGroupSpawn;
import com.linbit.linstor.api.model.ResourceMakeAvailable; import com.linbit.linstor.api.model.ResourceMakeAvailable;
import com.linbit.linstor.api.model.ResourceWithVolumes;
import com.linbit.linstor.api.model.Snapshot; import com.linbit.linstor.api.model.Snapshot;
import com.linbit.linstor.api.model.SnapshotRestore; import com.linbit.linstor.api.model.SnapshotRestore;
import com.linbit.linstor.api.model.VolumeDefinition; import com.linbit.linstor.api.model.VolumeDefinition;
@ -134,6 +134,9 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
@Inject @Inject
private HostDao _hostDao; private HostDao _hostDao;
private long volumeStatsLastUpdate = 0L;
private final Map<String, Pair<Long, Long>> volumeStats = new HashMap<>();
public LinstorPrimaryDataStoreDriverImpl() public LinstorPrimaryDataStoreDriverImpl()
{ {
} }
@ -403,9 +406,9 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
} }
} }
private String getRscGrp(StoragePoolVO storagePoolVO) { private String getRscGrp(StoragePool storagePool) {
return storagePoolVO.getUserInfo() != null && !storagePoolVO.getUserInfo().isEmpty() ? return storagePool.getUserInfo() != null && !storagePool.getUserInfo().isEmpty() ?
storagePoolVO.getUserInfo() : "DfltRscGrp"; storagePool.getUserInfo() : "DfltRscGrp";
} }
/** /**
@ -618,7 +621,7 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
*/ */
private void updateRscGrpIfNecessary(DevelopersApi api, String rscName, String tgtRscGrp) throws ApiException { private void updateRscGrpIfNecessary(DevelopersApi api, String rscName, String tgtRscGrp) throws ApiException {
List<ResourceDefinition> rscDfns = api.resourceDefinitionList( List<ResourceDefinition> rscDfns = api.resourceDefinitionList(
Collections.singletonList(rscName), null, null, null); Collections.singletonList(rscName), false, null, null, null);
if (rscDfns != null && !rscDfns.isEmpty()) { if (rscDfns != null && !rscDfns.isEmpty()) {
ResourceDefinition rscDfn = rscDfns.get(0); ResourceDefinition rscDfn = rscDfns.get(0);
@ -648,7 +651,7 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
private void deleteTemplateForProps( private void deleteTemplateForProps(
DevelopersApi api, String rscName) throws ApiException { DevelopersApi api, String rscName) throws ApiException {
List<ResourceDefinition> rdList = api.resourceDefinitionList( List<ResourceDefinition> rdList = api.resourceDefinitionList(
Collections.singletonList(rscName), null, null, null); Collections.singletonList(rscName), false, null, null, null);
if (CollectionUtils.isNotEmpty(rdList)) { if (CollectionUtils.isNotEmpty(rdList)) {
ResourceDefinitionModify rdm = new ResourceDefinitionModify(); ResourceDefinitionModify rdm = new ResourceDefinitionModify();
@ -1506,22 +1509,77 @@ public class LinstorPrimaryDataStoreDriverImpl implements PrimaryDataStoreDriver
@Override @Override
public boolean canProvideStorageStats() { public boolean canProvideStorageStats() {
return false; return true;
} }
@Override @Override
public Pair<Long, Long> getStorageStats(StoragePool storagePool) { public Pair<Long, Long> getStorageStats(StoragePool storagePool) {
return null; logger.debug(String.format("Requesting storage stats: %s", storagePool));
return LinstorUtil.getStorageStats(storagePool.getHostAddress(), getRscGrp(storagePool));
} }
@Override @Override
public boolean canProvideVolumeStats() { public boolean canProvideVolumeStats() {
return false; return LinstorConfigurationManager.VolumeStatsCacheTime.value() > 0;
}
/**
* Updates the cache map containing current allocated size data.
* @param api Linstor Developers api object
*/
private void fillVolumeStatsCache(DevelopersApi api) {
try {
logger.trace("Start volume stats cache update");
List<ResourceWithVolumes> resources = api.viewResources(
Collections.emptyList(),
Collections.emptyList(),
Collections.emptyList(),
null,
null,
null);
List<ResourceDefinition> rscDfns = api.resourceDefinitionList(
Collections.emptyList(), true, null, null, null);
HashMap<String, Long> resSizeMap = new HashMap<>();
for (ResourceDefinition rscDfn : rscDfns) {
if (CollectionUtils.isNotEmpty(rscDfn.getVolumeDefinitions())) {
resSizeMap.put(rscDfn.getName(), rscDfn.getVolumeDefinitions().get(0).getSizeKib() * 1024);
}
}
HashMap<String, Long> allocSizeMap = new HashMap<>();
for (ResourceWithVolumes rsc : resources) {
if (!LinstorUtil.isRscDiskless(rsc) && !rsc.getVolumes().isEmpty()) {
long allocatedBytes = allocSizeMap.getOrDefault(rsc.getName(), 0L);
allocSizeMap.put(rsc.getName(), Math.max(allocatedBytes, rsc.getVolumes().get(0).getAllocatedSizeKib() * 1024));
}
}
volumeStats.clear();
for (Map.Entry<String, Long> entry : allocSizeMap.entrySet()) {
Long reserved = resSizeMap.getOrDefault(entry.getKey(), 0L);
Pair<Long, Long> volStat = new Pair<>(entry.getValue(), reserved);
volumeStats.put(entry.getKey(), volStat);
}
volumeStatsLastUpdate = System.currentTimeMillis();
logger.trace("Done volume stats cache update: {}", volumeStats.size());
} catch (ApiException e) {
logger.error("Unable to fetch Linstor resources: {}", e.getBestMessage());
}
} }
@Override @Override
public Pair<Long, Long> getVolumeStats(StoragePool storagePool, String volumeId) { public Pair<Long, Long> getVolumeStats(StoragePool storagePool, String volumeId) {
return null; final DevelopersApi api = LinstorUtil.getLinstorAPI(storagePool.getHostAddress());
synchronized (volumeStats) {
long invalidateCacheTime = volumeStatsLastUpdate +
LinstorConfigurationManager.VolumeStatsCacheTime.value() * 1000;
if (invalidateCacheTime < System.currentTimeMillis()) {
fillVolumeStatsCache(api);
}
return volumeStats.get(LinstorUtil.RSC_PREFIX + volumeId);
}
} }
@Override @Override

View File

@ -24,7 +24,14 @@ public class LinstorConfigurationManager implements Configurable
public static final ConfigKey<Boolean> BackupSnapshots = new ConfigKey<>(Boolean.class, "lin.backup.snapshots", "Advanced", "true", public static final ConfigKey<Boolean> BackupSnapshots = new ConfigKey<>(Boolean.class, "lin.backup.snapshots", "Advanced", "true",
"Backup Linstor primary storage snapshots to secondary storage (deleting ps snapshot)", true, ConfigKey.Scope.Global, null); "Backup Linstor primary storage snapshots to secondary storage (deleting ps snapshot)", true, ConfigKey.Scope.Global, null);
public static final ConfigKey<?>[] CONFIG_KEYS = new ConfigKey<?>[] { BackupSnapshots }; public static final ConfigKey<Integer> VolumeStatsCacheTime = new ConfigKey<>("Advanced", Integer.class,
"lin.volumes.stats.cachetime", "300",
"Cache time of volume stats for Linstor volumes. 0 to disable volume stats",
false);
public static final ConfigKey<?>[] CONFIG_KEYS = new ConfigKey<?>[] {
BackupSnapshots, VolumeStatsCacheTime
};
@Override @Override
public String getConfigComponentName() public String getConfigComponentName()

View File

@ -196,6 +196,30 @@ public class LinstorUtil {
} }
} }
public static Pair<Long, Long> getStorageStats(String linstorUrl, String rscGroupName) {
DevelopersApi linstorApi = getLinstorAPI(linstorUrl);
try {
List<StoragePool> storagePools = LinstorUtil.getRscGroupStoragePools(linstorApi, rscGroupName);
long capacity = storagePools.stream()
.filter(sp -> sp.getProviderKind() != ProviderKind.DISKLESS)
.mapToLong(sp -> sp.getTotalCapacity() != null ? sp.getTotalCapacity() : 0L)
.sum() * 1024; // linstor uses kiB
long used = storagePools.stream()
.filter(sp -> sp.getProviderKind() != ProviderKind.DISKLESS)
.mapToLong(sp -> sp.getTotalCapacity() != null && sp.getFreeCapacity() != null ?
sp.getTotalCapacity() - sp.getFreeCapacity() : 0L)
.sum() * 1024; // linstor uses Kib
LOGGER.debug(
String.format("Linstor(%s;%s): storageStats -> %d/%d", linstorUrl, rscGroupName, capacity, used));
return new Pair<>(capacity, used);
} catch (ApiException apiEx) {
LOGGER.error(apiEx.getMessage());
throw new CloudRuntimeException(apiEx.getBestMessage(), apiEx);
}
}
/** /**
* Check if any resource of the given name is InUse on any host. * Check if any resource of the given name is InUse on any host.
* *
@ -304,7 +328,7 @@ public class LinstorUtil {
public static List<ResourceDefinition> getRDListStartingWith(DevelopersApi api, String startWith) public static List<ResourceDefinition> getRDListStartingWith(DevelopersApi api, String startWith)
throws ApiException throws ApiException
{ {
List<ResourceDefinition> rscDfns = api.resourceDefinitionList(null, null, null, null); List<ResourceDefinition> rscDfns = api.resourceDefinitionList(null, false, null, null, null);
return rscDfns.stream() return rscDfns.stream()
.filter(rscDfn -> rscDfn.getName().toLowerCase().startsWith(startWith.toLowerCase())) .filter(rscDfn -> rscDfn.getName().toLowerCase().startsWith(startWith.toLowerCase()))
@ -387,7 +411,7 @@ public class LinstorUtil {
*/ */
public static ResourceDefinition findResourceDefinition(DevelopersApi api, String rscName, String rscGrpName) public static ResourceDefinition findResourceDefinition(DevelopersApi api, String rscName, String rscGrpName)
throws ApiException { throws ApiException {
List<ResourceDefinition> rscDfns = api.resourceDefinitionList(null, null, null, null); List<ResourceDefinition> rscDfns = api.resourceDefinitionList(null, false, null, null, null);
List<ResourceDefinition> rdsStartingWith = rscDfns.stream() List<ResourceDefinition> rdsStartingWith = rscDfns.stream()
.filter(rscDfn -> rscDfn.getName().toLowerCase().startsWith(rscName.toLowerCase())) .filter(rscDfn -> rscDfn.getName().toLowerCase().startsWith(rscName.toLowerCase()))
@ -403,4 +427,8 @@ public class LinstorUtil {
return rd.orElseGet(() -> rdsStartingWith.get(0)); return rd.orElseGet(() -> rdsStartingWith.get(0));
} }
public static boolean isRscDiskless(ResourceWithVolumes rsc) {
return rsc.getFlags() != null && rsc.getFlags().contains(ApiConsts.FLAG_DISKLESS);
}
} }

View File

@ -175,7 +175,7 @@
<cs.nitro.version>10.1</cs.nitro.version> <cs.nitro.version>10.1</cs.nitro.version>
<cs.opensaml.version>2.6.6</cs.opensaml.version> <cs.opensaml.version>2.6.6</cs.opensaml.version>
<cs.rados-java.version>0.6.0</cs.rados-java.version> <cs.rados-java.version>0.6.0</cs.rados-java.version>
<cs.java-linstor.version>0.6.0</cs.java-linstor.version> <cs.java-linstor.version>0.6.1</cs.java-linstor.version>
<cs.reflections.version>0.10.2</cs.reflections.version> <cs.reflections.version>0.10.2</cs.reflections.version>
<cs.servicemix.version>3.4.4_1</cs.servicemix.version> <cs.servicemix.version>3.4.4_1</cs.servicemix.version>
<cs.servlet.version>4.0.1</cs.servlet.version> <cs.servlet.version>4.0.1</cs.servlet.version>

View File

@ -19,6 +19,7 @@ package com.cloud.alert;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -88,41 +89,55 @@ import com.cloud.utils.Pair;
import com.cloud.utils.component.ManagerBase; import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.concurrency.NamedThreadFactory; import com.cloud.utils.concurrency.NamedThreadFactory;
import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria;
import org.jetbrains.annotations.Nullable;
public class AlertManagerImpl extends ManagerBase implements AlertManager, Configurable { public class AlertManagerImpl extends ManagerBase implements AlertManager, Configurable {
protected Logger logger = LogManager.getLogger(AlertManagerImpl.class.getName()); protected Logger logger = LogManager.getLogger(AlertManagerImpl.class.getName());
public static final List<AlertType> ALERTS = Arrays.asList(AlertType.ALERT_TYPE_HOST
, AlertType.ALERT_TYPE_USERVM
, AlertType.ALERT_TYPE_DOMAIN_ROUTER
, AlertType.ALERT_TYPE_CONSOLE_PROXY
, AlertType.ALERT_TYPE_SSVM
, AlertType.ALERT_TYPE_STORAGE_MISC
, AlertType.ALERT_TYPE_MANAGEMENT_NODE
, AlertType.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED
, AlertType.ALERT_TYPE_UPLOAD_FAILED
, AlertType.ALERT_TYPE_OOBM_AUTH_ERROR
, AlertType.ALERT_TYPE_HA_ACTION
, AlertType.ALERT_TYPE_CA_CERT);
private static final long INITIAL_CAPACITY_CHECK_DELAY = 30L * 1000L; // Thirty seconds expressed in milliseconds. private static final long INITIAL_CAPACITY_CHECK_DELAY = 30L * 1000L; // Thirty seconds expressed in milliseconds.
private static final DecimalFormat DfPct = new DecimalFormat("###.##"); private static final DecimalFormat DfPct = new DecimalFormat("###.##");
private static final DecimalFormat DfWhole = new DecimalFormat("########"); private static final DecimalFormat DfWhole = new DecimalFormat("########");
@Inject @Inject
private AlertDao _alertDao; AlertDao _alertDao;
@Inject @Inject
protected StorageManager _storageMgr; protected StorageManager _storageMgr;
@Inject @Inject
protected CapacityManager _capacityMgr; protected CapacityManager _capacityMgr;
@Inject @Inject
private CapacityDao _capacityDao; CapacityDao _capacityDao;
@Inject @Inject
private DataCenterDao _dcDao; DataCenterDao _dcDao;
@Inject @Inject
private HostPodDao _podDao; HostPodDao _podDao;
@Inject @Inject
private ClusterDao _clusterDao; ClusterDao _clusterDao;
@Inject @Inject
private IPAddressDao _publicIPAddressDao; IPAddressDao _publicIPAddressDao;
@Inject @Inject
private DataCenterIpAddressDao _privateIPAddressDao; DataCenterIpAddressDao _privateIPAddressDao;
@Inject @Inject
private PrimaryDataStoreDao _storagePoolDao; PrimaryDataStoreDao _storagePoolDao;
@Inject @Inject
private ConfigurationDao _configDao; ConfigurationDao _configDao;
@Inject @Inject
private ResourceManager _resourceMgr; ResourceManager _resourceMgr;
@Inject @Inject
private ConfigurationManager _configMgr; ConfigurationManager _configMgr;
@Inject @Inject
protected ConfigDepot _configDepot; protected ConfigDepot _configDepot;
@Inject @Inject
@ -138,7 +153,7 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
private double _vlanCapacityThreshold = 0.75; private double _vlanCapacityThreshold = 0.75;
private double _directNetworkPublicIpCapacityThreshold = 0.75; private double _directNetworkPublicIpCapacityThreshold = 0.75;
private double _localStorageCapacityThreshold = 0.75; private double _localStorageCapacityThreshold = 0.75;
Map<Short, Double> _capacityTypeThresholdMap = new HashMap<Short, Double>(); Map<Short, Double> _capacityTypeThresholdMap = new HashMap<>();
private final ExecutorService _executor; private final ExecutorService _executor;
@ -402,18 +417,15 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
private void createOrUpdateVlanCapacity(long dcId, AllocationState capacityState) { private void createOrUpdateVlanCapacity(long dcId, AllocationState capacityState) {
SearchCriteria<CapacityVO> capacitySC = _capacityDao.createSearchCriteria(); SearchCriteria<CapacityVO> capacitySC = _capacityDao.createSearchCriteria();
List<CapacityVO> capacities = _capacityDao.search(capacitySC, null);
capacitySC = _capacityDao.createSearchCriteria();
capacitySC.addAnd("dataCenterId", SearchCriteria.Op.EQ, dcId); capacitySC.addAnd("dataCenterId", SearchCriteria.Op.EQ, dcId);
capacitySC.addAnd("capacityType", SearchCriteria.Op.EQ, Capacity.CAPACITY_TYPE_VLAN); capacitySC.addAnd("capacityType", SearchCriteria.Op.EQ, Capacity.CAPACITY_TYPE_VLAN);
capacities = _capacityDao.search(capacitySC, null); List<CapacityVO> capacities = _capacityDao.search(capacitySC, null);
int totalVlans = _dcDao.countZoneVlans(dcId, false); int totalVlans = _dcDao.countZoneVlans(dcId, false);
int allocatedVlans = _dcDao.countZoneVlans(dcId, true); int allocatedVlans = _dcDao.countZoneVlans(dcId, true);
CapacityState vlanCapacityState = (capacityState == AllocationState.Disabled) ? CapacityState.Disabled : CapacityState.Enabled; CapacityState vlanCapacityState = (capacityState == AllocationState.Disabled) ? CapacityState.Disabled : CapacityState.Enabled;
if (capacities.size() == 0) { if (capacities.isEmpty()) {
CapacityVO newVlanCapacity = new CapacityVO(null, dcId, null, null, allocatedVlans, totalVlans, Capacity.CAPACITY_TYPE_VLAN); CapacityVO newVlanCapacity = new CapacityVO(null, dcId, null, null, allocatedVlans, totalVlans, Capacity.CAPACITY_TYPE_VLAN);
newVlanCapacity.setCapacityState(vlanCapacityState); newVlanCapacity.setCapacityState(vlanCapacityState);
_capacityDao.persist(newVlanCapacity); _capacityDao.persist(newVlanCapacity);
@ -430,16 +442,13 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
public void createOrUpdateIpCapacity(Long dcId, Long podId, short capacityType, AllocationState capacityState) { public void createOrUpdateIpCapacity(Long dcId, Long podId, short capacityType, AllocationState capacityState) {
SearchCriteria<CapacityVO> capacitySC = _capacityDao.createSearchCriteria(); SearchCriteria<CapacityVO> capacitySC = _capacityDao.createSearchCriteria();
List<CapacityVO> capacities = _capacityDao.search(capacitySC, null);
capacitySC = _capacityDao.createSearchCriteria();
capacitySC.addAnd("podId", SearchCriteria.Op.EQ, podId); capacitySC.addAnd("podId", SearchCriteria.Op.EQ, podId);
capacitySC.addAnd("dataCenterId", SearchCriteria.Op.EQ, dcId); capacitySC.addAnd("dataCenterId", SearchCriteria.Op.EQ, dcId);
capacitySC.addAnd("capacityType", SearchCriteria.Op.EQ, capacityType); capacitySC.addAnd("capacityType", SearchCriteria.Op.EQ, capacityType);
int totalIPs; int totalIPs;
int allocatedIPs; int allocatedIPs;
capacities = _capacityDao.search(capacitySC, null); List<CapacityVO> capacities = _capacityDao.search(capacitySC, null);
if (capacityType == Capacity.CAPACITY_TYPE_PRIVATE_IP) { if (capacityType == Capacity.CAPACITY_TYPE_PRIVATE_IP) {
totalIPs = _privateIPAddressDao.countIPs(podId, dcId, false); totalIPs = _privateIPAddressDao.countIPs(podId, dcId, false);
allocatedIPs = _privateIPAddressDao.countIPs(podId, dcId, true); allocatedIPs = _privateIPAddressDao.countIPs(podId, dcId, true);
@ -452,7 +461,7 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
} }
CapacityState ipCapacityState = (capacityState == AllocationState.Disabled) ? CapacityState.Disabled : CapacityState.Enabled; CapacityState ipCapacityState = (capacityState == AllocationState.Disabled) ? CapacityState.Disabled : CapacityState.Enabled;
if (capacities.size() == 0) { if (capacities.isEmpty()) {
CapacityVO newPublicIPCapacity = new CapacityVO(null, dcId, podId, null, allocatedIPs, totalIPs, capacityType); CapacityVO newPublicIPCapacity = new CapacityVO(null, dcId, podId, null, allocatedIPs, totalIPs, capacityType);
newPublicIPCapacity.setCapacityState(ipCapacityState); newPublicIPCapacity.setCapacityState(ipCapacityState);
_capacityDao.persist(newPublicIPCapacity); _capacityDao.persist(newPublicIPCapacity);
@ -477,7 +486,7 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
int total = usedTotal.second(); int total = usedTotal.second();
int allocated = usedTotal.first(); int allocated = usedTotal.first();
CapacityState state = (capacityState == AllocationState.Disabled) ? CapacityState.Disabled : CapacityState.Enabled; CapacityState state = (capacityState == AllocationState.Disabled) ? CapacityState.Disabled : CapacityState.Enabled;
if (capacities.size() == 0) { if (capacities.isEmpty()) {
CapacityVO capacityVO = new CapacityVO(null, dcId, null, null, allocated, total, capacityType); CapacityVO capacityVO = new CapacityVO(null, dcId, null, null, allocated, total, capacityType);
capacityVO.setCapacityState(state); capacityVO.setCapacityState(state);
_capacityDao.persist(capacityVO); _capacityDao.persist(capacityVO);
@ -524,13 +533,12 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
// Generate Alerts for Zone Level capacities // Generate Alerts for Zone Level capacities
for (DataCenterVO dc : dataCenterList) { for (DataCenterVO dc : dataCenterList) {
for (Short capacityType : dataCenterCapacityTypes) { for (Short capacityType : dataCenterCapacityTypes) {
List<SummedCapacity> capacity = new ArrayList<SummedCapacity>(); List<SummedCapacity> capacity = _capacityDao.findCapacityBy(capacityType.intValue(), dc.getId(), null, null);
capacity = _capacityDao.findCapacityBy(capacityType.intValue(), dc.getId(), null, null);
if (capacityType == Capacity.CAPACITY_TYPE_SECONDARY_STORAGE) { if (capacityType == Capacity.CAPACITY_TYPE_SECONDARY_STORAGE) {
capacity.add(getUsedStats(capacityType, dc.getId(), null, null)); capacity.add(getUsedStats(capacityType, dc.getId(), null, null));
} }
if (capacity == null || capacity.size() == 0) { if (capacity == null || capacity.isEmpty()) {
continue; continue;
} }
double totalCapacity = capacity.get(0).getTotalCapacity(); double totalCapacity = capacity.get(0).getTotalCapacity();
@ -545,7 +553,7 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
for (HostPodVO pod : podList) { for (HostPodVO pod : podList) {
for (Short capacityType : podCapacityTypes) { for (Short capacityType : podCapacityTypes) {
List<SummedCapacity> capacity = _capacityDao.findCapacityBy(capacityType.intValue(), pod.getDataCenterId(), pod.getId(), null); List<SummedCapacity> capacity = _capacityDao.findCapacityBy(capacityType.intValue(), pod.getDataCenterId(), pod.getId(), null);
if (capacity == null || capacity.size() == 0) { if (capacity == null || capacity.isEmpty()) {
continue; continue;
} }
double totalCapacity = capacity.get(0).getTotalCapacity(); double totalCapacity = capacity.get(0).getTotalCapacity();
@ -559,11 +567,10 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
// Generate Alerts for Cluster Level capacities // Generate Alerts for Cluster Level capacities
for (ClusterVO cluster : clusterList) { for (ClusterVO cluster : clusterList) {
for (Short capacityType : clusterCapacityTypes) { for (Short capacityType : clusterCapacityTypes) {
List<SummedCapacity> capacity = new ArrayList<SummedCapacity>(); List<SummedCapacity> capacity = _capacityDao.findCapacityBy(capacityType.intValue(), cluster.getDataCenterId(), null, cluster.getId());
capacity = _capacityDao.findCapacityBy(capacityType.intValue(), cluster.getDataCenterId(), null, cluster.getId());
// cpu and memory allocated capacity notification threshold can be defined at cluster level, so getting the value if they are defined at cluster level // cpu and memory allocated capacity notification threshold can be defined at cluster level, so getting the value if they are defined at cluster level
double threshold = 0; double threshold;
switch (capacityType) { switch (capacityType) {
case Capacity.CAPACITY_TYPE_STORAGE: case Capacity.CAPACITY_TYPE_STORAGE:
capacity.add(getUsedStats(capacityType, cluster.getDataCenterId(), cluster.getPodId(), cluster.getId())); capacity.add(getUsedStats(capacityType, cluster.getDataCenterId(), cluster.getPodId(), cluster.getId()));
@ -581,7 +588,7 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
default: default:
threshold = _capacityTypeThresholdMap.get(capacityType); threshold = _capacityTypeThresholdMap.get(capacityType);
} }
if (capacity == null || capacity.size() == 0) { if (capacity == null || capacity.isEmpty()) {
continue; continue;
} }
@ -697,7 +704,7 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
private List<Short> getCapacityTypesAtZoneLevel() { private List<Short> getCapacityTypesAtZoneLevel() {
List<Short> dataCenterCapacityTypes = new ArrayList<Short>(); List<Short> dataCenterCapacityTypes = new ArrayList<>();
dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_PUBLIC_IP); dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_VIRTUAL_NETWORK_PUBLIC_IP);
dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_DIRECT_ATTACHED_PUBLIC_IP); dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_DIRECT_ATTACHED_PUBLIC_IP);
dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_SECONDARY_STORAGE); dataCenterCapacityTypes.add(Capacity.CAPACITY_TYPE_SECONDARY_STORAGE);
@ -709,7 +716,7 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
private List<Short> getCapacityTypesAtPodLevel() { private List<Short> getCapacityTypesAtPodLevel() {
List<Short> podCapacityTypes = new ArrayList<Short>(); List<Short> podCapacityTypes = new ArrayList<>();
podCapacityTypes.add(Capacity.CAPACITY_TYPE_PRIVATE_IP); podCapacityTypes.add(Capacity.CAPACITY_TYPE_PRIVATE_IP);
return podCapacityTypes; return podCapacityTypes;
@ -717,7 +724,7 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
private List<Short> getCapacityTypesAtClusterLevel() { private List<Short> getCapacityTypesAtClusterLevel() {
List<Short> clusterCapacityTypes = new ArrayList<Short>(); List<Short> clusterCapacityTypes = new ArrayList<>();
clusterCapacityTypes.add(Capacity.CAPACITY_TYPE_CPU); clusterCapacityTypes.add(Capacity.CAPACITY_TYPE_CPU);
clusterCapacityTypes.add(Capacity.CAPACITY_TYPE_MEMORY); clusterCapacityTypes.add(Capacity.CAPACITY_TYPE_MEMORY);
clusterCapacityTypes.add(Capacity.CAPACITY_TYPE_STORAGE); clusterCapacityTypes.add(Capacity.CAPACITY_TYPE_STORAGE);
@ -748,19 +755,11 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
public void sendAlert(AlertType alertType, DataCenter dataCenter, Pod pod, Cluster cluster, String subject, String content) public void sendAlert(AlertType alertType, DataCenter dataCenter, Pod pod, Cluster cluster, String subject, String content)
throws MessagingException, UnsupportedEncodingException { throws MessagingException, UnsupportedEncodingException {
logger.warn(String.format("alertType=[%s] dataCenter=[%s] pod=[%s] cluster=[%s] message=[%s].", alertType, dataCenter, pod, cluster, subject));
AlertVO alert = null;
Long clusterId = cluster == null ? null : cluster.getId(); Long clusterId = cluster == null ? null : cluster.getId();
Long podId = pod == null ? null : pod.getId(); Long podId = pod == null ? null : pod.getId();
long dcId = dataCenter == null ? 0L : dataCenter.getId(); long dcId = dataCenter == null ? 0L : dataCenter.getId();
if ((alertType != AlertManager.AlertType.ALERT_TYPE_HOST) && (alertType != AlertManager.AlertType.ALERT_TYPE_USERVM) logger.warn(String.format("alertType=[%s] dataCenterId=[%s] podId=[%s] clusterId=[%s] message=[%s].", alertType, dcId, podId, clusterId, subject));
&& (alertType != AlertManager.AlertType.ALERT_TYPE_DOMAIN_ROUTER) && (alertType != AlertManager.AlertType.ALERT_TYPE_CONSOLE_PROXY) AlertVO alert = getAlertForTrivialAlertType(alertType, dcId, podId, clusterId);
&& (alertType != AlertManager.AlertType.ALERT_TYPE_SSVM) && (alertType != AlertManager.AlertType.ALERT_TYPE_STORAGE_MISC)
&& (alertType != AlertManager.AlertType.ALERT_TYPE_MANAGEMENT_NODE) && (alertType != AlertManager.AlertType.ALERT_TYPE_RESOURCE_LIMIT_EXCEEDED)
&& (alertType != AlertManager.AlertType.ALERT_TYPE_UPLOAD_FAILED) && (alertType != AlertManager.AlertType.ALERT_TYPE_OOBM_AUTH_ERROR)
&& (alertType != AlertManager.AlertType.ALERT_TYPE_HA_ACTION) && (alertType != AlertManager.AlertType.ALERT_TYPE_CA_CERT)) {
alert = _alertDao.getLastAlert(alertType.getType(), dcId, podId, clusterId);
}
if (alert == null) { if (alert == null) {
AlertVO newAlert = new AlertVO(); AlertVO newAlert = new AlertVO();
@ -802,6 +801,15 @@ public class AlertManagerImpl extends ManagerBase implements AlertManager, Confi
} }
@Nullable
private AlertVO getAlertForTrivialAlertType(AlertType alertType, long dataCenterId, Long podId, Long clusterId) {
AlertVO alert = null;
if (!ALERTS.contains(alertType)) {
alert = _alertDao.getLastAlert(alertType.getType(), dataCenterId, podId, clusterId);
}
return alert;
}
protected void sendMessage(SMTPMailProperties mailProps) { protected void sendMessage(SMTPMailProperties mailProps) {
_executor.execute(new Runnable() { _executor.execute(new Runnable() {
@Override @Override

View File

@ -2909,6 +2909,12 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
Account callerAccount = _accountMgr.getActiveAccountById(user.getAccountId()); Account callerAccount = _accountMgr.getActiveAccountById(user.getAccountId());
_accountMgr.checkAccess(callerAccount, AccessType.OperateEntry, true, network); _accountMgr.checkAccess(callerAccount, AccessType.OperateEntry, true, network);
if (!network.isRedundant() && makeRedundant) { if (!network.isRedundant() && makeRedundant) {
NetworkOffering networkOffering = _entityMgr.findById(NetworkOffering.class, network.getNetworkOfferingId());
Map<Network.Capability, String> sourceNatCapabilities = getNetworkOfferingServiceCapabilities(networkOffering, Service.SourceNat);
String isRedundantRouterSupported = sourceNatCapabilities.get(Capability.RedundantRouter);
if (!Boolean.parseBoolean(isRedundantRouterSupported)) {
throw new InvalidParameterValueException(String.format("Redundant router is not supported by the network offering %s", networkOffering));
}
network.setRedundant(true); network.setRedundant(true);
if (!_networksDao.update(network.getId(), network)) { if (!_networksDao.update(network.getId(), network)) {
throw new CloudRuntimeException("Failed to update network into a redundant one, please try again"); throw new CloudRuntimeException("Failed to update network into a redundant one, please try again");