package org.ovirt.engine.core.bll.storage.pool; import java.util.HashMap; import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; import org.ovirt.engine.core.bll.Backend; import org.ovirt.engine.core.common.AuditLogType; import org.ovirt.engine.core.common.action.SetStoragePoolStatusParameters; import org.ovirt.engine.core.common.action.VdcActionType; import org.ovirt.engine.core.common.businessentities.StoragePool; import org.ovirt.engine.core.common.businessentities.StoragePoolStatus; import org.ovirt.engine.core.common.businessentities.VDS; import org.ovirt.engine.core.common.businessentities.VDSStatus; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dal.dbbroker.DbFacade; import org.ovirt.engine.core.di.Injector; import org.ovirt.engine.core.utils.timer.OnTimerMethodAnnotation; import org.ovirt.engine.core.utils.timer.SchedulerUtil; import org.ovirt.engine.core.utils.timer.SchedulerUtilQuartzImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public final class StoragePoolStatusHandler { private static final Logger log = LoggerFactory.getLogger(StoragePoolStatusHandler.class); private static HashMap<Guid, StoragePoolStatusHandler> nonOperationalPools = new HashMap<>(); private final Guid poolId; private final SchedulerUtilQuartzImpl schedulerUtil; private String timerId; private StoragePoolStatusHandler(Guid poolId, SchedulerUtilQuartzImpl schedulerUtil) { Objects.requireNonNull(schedulerUtil, "schedulerUtil cannot be null"); this.poolId = poolId; this.schedulerUtil = schedulerUtil; this.timerId = null; } protected SchedulerUtil getScheduler() { return schedulerUtil; } private StoragePoolStatusHandler scheduleTimeout() { Class[] argTypes = new Class[0]; Object[] args = new Object[0]; Integer timeout = Config.<Integer> getValue(ConfigValues.StoragePoolNonOperationalResetTimeoutInMin); timerId = getScheduler().scheduleAOneTimeJob(this, "onTimeout", argTypes, args, timeout, TimeUnit.MINUTES); return this; } private void deScheduleTimeout() { if (timerId != null) { getScheduler().deleteJob(timerId); timerId = null; } } @OnTimerMethodAnnotation("onTimeout") public void onTimeout() { if (nonOperationalPools.containsKey(poolId)) { try { StoragePool pool = DbFacade.getInstance().getStoragePoolDao().get(poolId); if (pool != null && pool.getStatus() == StoragePoolStatus.NotOperational) { nonOperationalPoolTreatment(pool); } } catch (Exception ignore) { } } } public static void poolStatusChanged(Guid poolId, StoragePoolStatus status) { if (nonOperationalPools.containsKey(poolId) && status != StoragePoolStatus.NotOperational) { StoragePoolStatusHandler handler = nonOperationalPools.get(poolId); if (handler != null) { synchronized (handler) { handler.deScheduleTimeout(); } } synchronized (nonOperationalPools) { nonOperationalPools.remove(poolId); } } else if (status == StoragePoolStatus.NotOperational) { synchronized (nonOperationalPools) { final SchedulerUtilQuartzImpl schedulerUtil = Injector.get(SchedulerUtilQuartzImpl.class); final StoragePoolStatusHandler storagePoolStatusHandler = new StoragePoolStatusHandler( poolId, schedulerUtil); nonOperationalPools.put(poolId, storagePoolStatusHandler.scheduleTimeout()); } } } private static void nonOperationalPoolTreatment(StoragePool pool) { boolean changeStatus = false; if (getAllRunningVdssInPool(pool).size() > 0) { changeStatus = true; } if (changeStatus) { log.info("Moving data center '{}' with Id '{}' to status Problematic from status NotOperational on a one" + " time basis to try to recover", pool.getName(), pool.getId()); Backend.getInstance().runInternalAction( VdcActionType.SetStoragePoolStatus, new SetStoragePoolStatusParameters(pool.getId(), StoragePoolStatus.NonResponsive, AuditLogType.SYSTEM_CHANGE_STORAGE_POOL_STATUS_PROBLEMATIC_FROM_NON_OPERATIONAL)); synchronized (nonOperationalPools) { nonOperationalPools.remove(pool.getId()); } } } private static List<VDS> getAllRunningVdssInPool(StoragePool pool) { return DbFacade.getInstance().getVdsDao().getAllForStoragePoolAndStatus(pool.getId(), VDSStatus.Up); } public static void init() { List<StoragePool> allPools = DbFacade.getInstance().getStoragePoolDao().getAll(); for (StoragePool pool : allPools) { if (pool.getStatus() == StoragePoolStatus.NotOperational) { poolStatusChanged(pool.getId(), StoragePoolStatus.NotOperational); } } } }