Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions conf/globalConfig/primaryStorage.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,12 @@
<type>java.lang.Integer</type>
<category>primaryStorage</category>
</config>

<config>
<name>primarystorage.host.status.refresh.interval</name>
<category>primaryStorage</category>
<description>The interval to refresh ps and host connection status, in seconds</description>
<defaultValue>60</defaultValue>
<type>java.lang.Integer</type>
</config>
</globalConfig>
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ public class PrimaryStorageType {
private PrimaryStorageFindBackupStorage primaryStorageFindBackupStorage;
private boolean supportCreateVolumeSnapshotCheckCapacity = true;

private boolean supportCheckHostStatus=false;

public boolean isSupportSharedVolume() {
return supportSharedVolume;
}
Expand Down Expand Up @@ -200,4 +202,12 @@ public boolean isSupportStorageTrash() {
public void setSupportStorageTrash(boolean supportStorageTrash) {
this.supportStorageTrash = supportStorageTrash;
}

public boolean isSupportCheckHostStatus(){
return supportCheckHostStatus;
}

public void setSupportCheckHostStatus(boolean supportCheckHostStatus) {
this.supportCheckHostStatus = supportCheckHostStatus;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.zstack.kvm.KVMHostConnectedContext;
import org.zstack.kvm.KVMHostFactory;
import org.zstack.storage.ceph.CephConstants;
import org.zstack.storage.primary.CheckHostStorageConnectionMsg;

import javax.persistence.TypedQuery;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public class CephPrimaryStorageFactory implements PrimaryStorageFactory, CephCap

{
type.setSupportSharedVolume(true);
type.setSupportCheckHostStatus(true);
}

@Autowired
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
package org.zstack.storage.ceph.primary;

import org.zstack.header.message.NeedReplyMessage;
import org.zstack.header.storage.primary.PrimaryStorageMessage;

import java.util.List;

public class CheckHostStorageConnectionMsg extends NeedReplyMessage implements PrimaryStorageMessage {
private String primaryStorageUuid;
private List<String> hostUuids;

@Override
public String getPrimaryStorageUuid() {
return primaryStorageUuid;
}

public void setPrimaryStorageUuid(String primaryStorageUuid) {
this.primaryStorageUuid = primaryStorageUuid;
}

public List<String> getHostUuids() {
return hostUuids;
}

public void setHostUuids(List<String> hostUuids) {
this.hostUuids = hostUuids;
}
package org.zstack.storage.primary;
import org.zstack.header.message.NeedReplyMessage;
import org.zstack.header.storage.primary.PrimaryStorageMessage;
import java.util.List;
public class CheckHostStorageConnectionMsg extends NeedReplyMessage implements PrimaryStorageMessage {
private String primaryStorageUuid;
private List<String> hostUuids;
@Override
public String getPrimaryStorageUuid() {
return primaryStorageUuid;
}
public void setPrimaryStorageUuid(String primaryStorageUuid) {
this.primaryStorageUuid = primaryStorageUuid;
}
public List<String> getHostUuids() {
return hostUuids;
}
public void setHostUuids(List<String> hostUuids) {
this.hostUuids = hostUuids;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.zstack.storage.ceph.primary;

import org.zstack.header.message.MessageReply;

public class CheckHostStorageConnectionReply extends MessageReply {
}
package org.zstack.storage.primary;
import org.zstack.header.message.MessageReply;
public class CheckHostStorageConnectionReply extends MessageReply {
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,6 @@ public class PrimaryStorageGlobalConfig {
@GlobalConfigDef(defaultValue = "1", type = Long.class)
public static GlobalConfig COLLECT_AND_FORECAST_INTERVAL = new GlobalConfig(CATEGORY, "collect.forecast.interval");

@GlobalConfigValidation(numberGreaterThan = 0)
public static GlobalConfig PRIMARY_STORAGE_HOST_STATUS_REFRESH_INTERVAL = new GlobalConfig(CATEGORY, "primarystorage.host.status.refresh.interval");
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.zstack.configuration.InstanceOfferingSystemTags;
import org.zstack.configuration.OfferingUserConfigUtils;
import org.zstack.core.Platform;
import org.zstack.core.asyncbatch.While;
import org.zstack.core.cloudbus.CloudBus;
import org.zstack.core.cloudbus.CloudBusCallBack;
import org.zstack.core.cloudbus.MessageSafe;
Expand All @@ -35,6 +36,7 @@
import org.zstack.header.configuration.userconfig.InstanceOfferingUserConfig;
import org.zstack.header.configuration.userconfig.InstanceOfferingUserConfigValidator;
import org.zstack.header.core.NoErrorCompletion;
import org.zstack.header.core.NopeWhileDoneCompletion;
import org.zstack.header.core.trash.InstallPathRecycleVO;
import org.zstack.header.core.trash.InstallPathRecycleVO_;
import org.zstack.header.errorcode.ErrorCode;
Expand Down Expand Up @@ -109,6 +111,8 @@ public class PrimaryStorageManagerImpl extends AbstractService implements Primar
private static final Map<String, List<PrimaryStorageExtensionFactory>> extensionFactories = Maps.newConcurrentMap();
private AutoDeleteTrashTask globalTrashTask;

private Future refreshPrimaryStorageHostStatusTask;

static {
allowedMessageAfterSoftDeletion.add(PrimaryStorageDeletionMsg.class);
}
Expand Down Expand Up @@ -1158,6 +1162,78 @@ public boolean stop() {
return true;
}

private void startPeriodTasks() {
PrimaryStorageGlobalConfig.PRIMARY_STORAGE_HOST_STATUS_REFRESH_INTERVAL.installUpdateExtension((oldConfig, newConfig) -> startRefreshPrimaryStorageHostStatusTask());
startRefreshPrimaryStorageHostStatusTask();
}

private synchronized void startRefreshPrimaryStorageHostStatusTask() {
if (refreshPrimaryStorageHostStatusTask != null) {
refreshPrimaryStorageHostStatusTask.cancel(true);
}

refreshPrimaryStorageHostStatusTask = thdf.submitPeriodicTask(new PeriodicTask() {
@Override
public TimeUnit getTimeUnit() {
return TimeUnit.SECONDS;
}

@Override
public long getInterval() {
return PrimaryStorageGlobalConfig.PRIMARY_STORAGE_HOST_STATUS_REFRESH_INTERVAL.value(Integer.class).longValue();
}

@Override
public String getName() {
return "update-host-storage-connection-status";
}

@Override
public void run() {
Map<String, List<String>> disconnectedHostsByPsUuid = new HashMap<>();

List<PrimaryStorageHostRefVO> refs = Q.New(PrimaryStorageHostRefVO.class)
.eq(PrimaryStorageHostRefVO_.status, PrimaryStorageHostStatus.Disconnected)
.list();

refs.forEach(ref -> {
disconnectedHostsByPsUuid.computeIfAbsent(ref.getPrimaryStorageUuid(), key -> new ArrayList<>()).add(ref.getHostUuid());
});


List<CheckHostStorageConnectionMsg> msgs = new ArrayList<>();
for (Map.Entry<String, List<String>> entry : disconnectedHostsByPsUuid.entrySet()) {
PrimaryStorageVO storageVO = dbf.findByUuid(entry.getKey(), PrimaryStorageVO.class);
if (!PrimaryStorageType.valueOf(storageVO.getType()).isSupportCheckHostStatus()){
continue;
}
CheckHostStorageConnectionMsg msg = new CheckHostStorageConnectionMsg();
msg.setPrimaryStorageUuid(entry.getKey());
msg.setHostUuids(entry.getValue());
bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, entry.getKey());
msgs.add(msg);
}
Comment on lines +1204 to +1215
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

修复潜在的空指针异常。

第1206行的dbf.findByUuid可能返回null,但代码未进行null检查就直接调用storageVO.getType(),会导致NullPointerException

🔎 建议的修复
 List<CheckHostStorageConnectionMsg> msgs = new ArrayList<>();
 for (Map.Entry<String, List<String>> entry : disconnectedHostsByPsUuid.entrySet()) {
     PrimaryStorageVO storageVO = dbf.findByUuid(entry.getKey(), PrimaryStorageVO.class);
+    if (storageVO == null) {
+        logger.warn(String.format("Primary storage[uuid:%s] not found, skipping host status check", entry.getKey()));
+        continue;
+    }
     if (!PrimaryStorageType.valueOf(storageVO.getType()).isSupportCheckHostStatus()){
         continue;
     }
     CheckHostStorageConnectionMsg msg = new CheckHostStorageConnectionMsg();
     msg.setPrimaryStorageUuid(entry.getKey());
     msg.setHostUuids(entry.getValue());
     bus.makeTargetServiceIdByResourceUuid(msg, PrimaryStorageConstant.SERVICE_ID, entry.getKey());
     msgs.add(msg);
 }
🤖 Prompt for AI Agents
In
storage/src/main/java/org/zstack/storage/primary/PrimaryStorageManagerImpl.java
around lines 1204 to 1215, dbf.findByUuid(...) can return null so calling
storageVO.getType() may throw a NullPointerException; add a null-check after
findByUuid and skip the entry (or log a warning) if storageVO is null before
accessing its type, then continue with the existing logic for non-null
storageVOs.


new While<>(msgs).step((msg, comp) -> {
bus.send(msg, new CloudBusCallBack(comp) {
@Override
public void run(MessageReply reply) {
if (!reply.isSuccess()) {
logger.error(String.format("Failed to check host storage connection for primary storage %s and host %s due to: %s",
msg.getPrimaryStorageUuid(), msg.getHostUuids().get(0), reply.getError()));
}
comp.done();
}
});
}, 10).run(new NopeWhileDoneCompletion());
}


});

}


private void populateExtensions() {
for (PrimaryStorageAllocatorStrategyFactory f : pluginRgty.getExtensionList(PrimaryStorageAllocatorStrategyFactory.class)) {
PrimaryStorageAllocatorStrategyFactory old = allocatorFactories.get(f.getPrimaryStorageAllocatorStrategyType().toString());
Expand Down Expand Up @@ -1264,6 +1340,7 @@ public void managementNodeReady() {
Platform.getManagementServerId()));
loadPrimaryStorage(false);
initResourcePrimaryStorageAutoDeleteTrash();
startPeriodTasks();
}

private void checkVmAllVolumePrimaryStorageState(String vmUuid) {
Expand Down