Ramesh N has uploaded a new change for review. Change subject: engine: sync job for gluster disk provisioning ......................................................................
engine: sync job for gluster disk provisioning Adding a sync job for gluster Disk Provisioning. It will monitor all the storage devices in the host and update the engine database accordingly. Change-Id: I651bb51873a96d491c5a5f51147cb72be958985a Signed-off-by: Ramesh Nachimuthu <[email protected]> --- M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterJob.java M backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterJobsManager.java A backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/StorageDeviceSyncJob.java A backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/SyncStorageDevicesCommand.java A backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/gluster/StorageDeviceSyncJobTest.java M backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java M backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java M backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/config/ConfigValues.java M backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java M backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/gluster/GlusterFeatureSupported.java M backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties M backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties M frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java M packaging/dbscripts/upgrade/pre_upgrade/0000_config.sql 14 files changed, 544 insertions(+), 0 deletions(-) git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/05/39705/1 diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterJob.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterJob.java index d2ac864..fc4f4a8 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterJob.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterJob.java @@ -33,6 +33,7 @@ import org.ovirt.engine.core.dao.gluster.GlusterServerServiceDao; import org.ovirt.engine.core.dao.gluster.GlusterServiceDao; import org.ovirt.engine.core.dao.gluster.GlusterVolumeDao; +import org.ovirt.engine.core.dao.gluster.StorageDeviceDao; import org.ovirt.engine.core.dao.network.InterfaceDao; import org.ovirt.engine.core.utils.lock.EngineLock; import org.ovirt.engine.core.utils.lock.LockManager; @@ -134,6 +135,9 @@ return DbFacade.getInstance().getGlusterGeoRepDao(); } + protected StorageDeviceDao getStorageDeviceDao() { + return DbFacade.getInstance().getStorageDeviceDao(); + } /** * Acquires a lock on the cluster with given id and locking group {@link LockingGroup#GLUSTER} * diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterJobsManager.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterJobsManager.java index 44c76cf..5297ca9 100644 --- a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterJobsManager.java +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterJobsManager.java @@ -2,6 +2,7 @@ import java.util.concurrent.TimeUnit; +import org.ovirt.engine.core.bll.utils.Injector; import org.ovirt.engine.core.common.config.Config; import org.ovirt.engine.core.common.config.ConfigValues; import org.ovirt.engine.core.common.mode.ApplicationMode; @@ -72,6 +73,15 @@ getRefreshRate(ConfigValues.GlusterRefreshRateGeoRepDiscoveryInSecs), TimeUnit.SECONDS); + StorageDeviceSyncJob StorageDeviceSyncJobInstance = Injector.get(StorageDeviceSyncJob.class); + scheduler.scheduleAFixedDelayJob(StorageDeviceSyncJobInstance, + "gluster_storage_device_pool_event", + new Class[0], + new Class[0], + getRefreshRate(ConfigValues.GlusterRefreshRateStorageDevices), + getRefreshRate(ConfigValues.GlusterRefreshRateStorageDevices), + TimeUnit.SECONDS); + scheduler.scheduleAFixedDelayJob(GlusterGeoRepSyncJob.getInstance(), "gluster_georepstatus_poll_event", new Class[0], diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/StorageDeviceSyncJob.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/StorageDeviceSyncJob.java new file mode 100644 index 0000000..57ae61e --- /dev/null +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/StorageDeviceSyncJob.java @@ -0,0 +1,186 @@ +package org.ovirt.engine.core.bll.gluster; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.Callable; + +import javax.inject.Singleton; + +import org.apache.commons.lang.StringUtils; +import org.ovirt.engine.core.common.AuditLogType; +import org.ovirt.engine.core.common.businessentities.VDS; +import org.ovirt.engine.core.common.businessentities.VDSGroup; +import org.ovirt.engine.core.common.businessentities.gluster.StorageDevice; +import org.ovirt.engine.core.common.gluster.GlusterFeatureSupported; +import org.ovirt.engine.core.common.utils.Pair; +import org.ovirt.engine.core.common.vdscommands.VDSCommandType; +import org.ovirt.engine.core.common.vdscommands.VDSReturnValue; +import org.ovirt.engine.core.common.vdscommands.VdsIdVDSCommandParametersBase; +import org.ovirt.engine.core.compat.Guid; +import org.ovirt.engine.core.utils.threadpool.ThreadPoolUtil; +import org.ovirt.engine.core.utils.timer.OnTimerMethodAnnotation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Singleton +public class StorageDeviceSyncJob extends GlusterJob { + private static final Logger log = LoggerFactory.getLogger(StorageDeviceSyncJob.class); + + public void init() { + log.info("Gluster Storage Device monitoring has been initialized"); + } + + @OnTimerMethodAnnotation("gluster_storage_device_pool_event") + public void refreshStorageDevices() { + // get all clusters + List<VDSGroup> clusters = getClusterDao().getAll(); + // for every cluster that supports disk provisioning + for (VDSGroup cluster : clusters) { + if (supportsGlusterDiskProvisioning(cluster)) { + refreshStorageDevicesFromServers(getClusterUtils().getAllUpServers(cluster.getId())); + } + } + } + + public void refreshStorageDevicesFromServers(List<VDS> upServers) { + List<Callable<Pair<VDS, List<StorageDevice>>>> storageDevicesListCalls = new ArrayList<>(); + + for (final VDS server : upServers) { + storageDevicesListCalls.add(new Callable<Pair<VDS, List<StorageDevice>>>() { + @Override + public Pair<VDS, List<StorageDevice>> call() throws Exception { + List<StorageDevice> storageDevices = getStorageDevicesFromServer(server); + return new Pair<VDS, List<StorageDevice>>(server, storageDevices); + } + }); + } + + if (!storageDevicesListCalls.isEmpty()) { + List<Pair<VDS, List<StorageDevice>>> storageDevices = ThreadPoolUtil.invokeAll(storageDevicesListCalls); + for (Pair<VDS, List<StorageDevice>> pair : storageDevices) { + if (pair.getSecond() != null) { + updateStorageDevices(pair.getFirst(), pair.getSecond()); + } + } + } + } + + private List<StorageDevice> getStorageDevicesFromServer(VDS server) { + try { + VDSReturnValue returnValue = + runVdsCommand(VDSCommandType.GetStorageDeviceList, + new VdsIdVDSCommandParametersBase(server.getId())); + if (returnValue.getSucceeded()) { + return (List<StorageDevice>) returnValue.getReturnValue(); + } else { + log.error("VDS error retriving storage device {}", returnValue.getVdsError().getMessage()); + log.debug("VDS Error", returnValue.getVdsError()); + return null; + } + } catch (Exception e) { + log.error("Exception retriving storage device from vds {}", e.getMessage()); + log.debug("Exception", e); + return null; + } + + } + + private void updateStorageDevices(VDS vds, List<StorageDevice> storageDevicesFromVdsm) { + Set<String> deviceUuidsFromVdsm = new HashSet<>(); + Set<String> deviceNamesFromVdsm = new HashSet<>(); + + List<StorageDevice> storageDevicesInDb = getStorageDeviceDao().getStorageDevicesInHost(vds.getId()); + Map<String, StorageDevice> nameToDeviceMap = new HashMap<>(); + Map<String, StorageDevice> deviceUuidToDeviceMap = new HashMap<>(); + + // Make deviceUuid to Device map and deviceName to device map so that we can find the + // newly added and updated devices without looping over the same list again and again. + for (StorageDevice storageDevice : storageDevicesInDb) { + nameToDeviceMap.put(storageDevice.getName(), storageDevice); + if (storageDevice.getDevUuid() != null && !storageDevice.getDevUuid().isEmpty()) { + deviceUuidToDeviceMap.put(storageDevice.getDevUuid(), storageDevice); + } + } + + List<StorageDevice> storageDevicesToUpdate = new ArrayList<>(); + List<StorageDevice> storageDevicesToDelete = new ArrayList<>(); + + for (StorageDevice storageDevice : storageDevicesFromVdsm) { + // Create deviceName and deviceUuid set to use it while finding the deleted services. + deviceNamesFromVdsm.add(storageDevice.getName()); + if (storageDevice.getDevUuid() != null) { + deviceUuidsFromVdsm.add(storageDevice.getDevUuid()); + } + // If DevUuid is already exits in the DB then its an existing devices + // Assume device from vdsm doesn't have devUUID, but device name already exists in the DB + // Following two cases possible: + // 1. If device in DB doesn't have a devUUID + // update the device if there is a change from vdsm. + // 2. If device in DB has devUUID + // Though name matches, its two different devices. So treat this device as new one. + // Device in DB will be updated/removed by some other iteration in the loop + + StorageDevice storageDevByDevUuid = deviceUuidToDeviceMap.get(storageDevice.getDevUuid()); + StorageDevice storageDevByName = nameToDeviceMap.get(storageDevice.getName()); + if (storageDevByDevUuid != null) { + storageDevice.setId(storageDevByDevUuid.getId()); + if (!Objects.equals(storageDevByDevUuid, storageDevice)) { + storageDevicesToUpdate.add(storageDevice); + } + } else if (storageDevByName != null && StringUtils.isBlank(storageDevByName.getDevUuid())) { + storageDevice.setId(storageDevByName.getId()); + if (!Objects.equals(storageDevByName, storageDevice)) { + storageDevicesToUpdate.add(storageDevice); + } + } else { + storageDevice.setId(Guid.newGuid()); + storageDevice.setVdsId(vds.getId()); + log.debug("detected new storage device '{}' for host '{}'", + storageDevice.getName(), + vds.getName()); + getStorageDeviceDao().save(storageDevice); + logStorageDeviceMessage(AuditLogType.NEW_STORAGE_DEVICE_DETECTED, + vds, + storageDevice); + } + } + + for (StorageDevice storageDevice : storageDevicesInDb) { + if ((storageDevice.getDevUuid() != null && !deviceUuidsFromVdsm.contains(storageDevice.getDevUuid())) + || (storageDevice.getDevUuid() == null && !deviceNamesFromVdsm.contains(storageDevice.getName()))) { + log.debug("storage device '{}' detected removed for the host '{}'", + storageDevice.getName(), + vds.getName()); + logStorageDeviceMessage(AuditLogType.STORAGE_DEVICE_REMOVED_FROM_THE_HOST, + vds, + storageDevice); + storageDevicesToDelete.add(storageDevice); + } + } + + if (!storageDevicesToUpdate.isEmpty()) { + getStorageDeviceDao().updateAllInBatch(storageDevicesToUpdate); + } + if (!storageDevicesToDelete.isEmpty()) { + getStorageDeviceDao().removeAllInBatch(storageDevicesToDelete); + } + + } + + private void logStorageDeviceMessage(AuditLogType logType, VDS vds, final StorageDevice device) { + logUtil.logAuditMessage(vds.getVdsGroupId(), null, vds, + logType, Collections.singletonMap("storageDevice", device.getName())); + } + + private boolean supportsGlusterDiskProvisioning(VDSGroup cluster) { + return cluster.supportsGlusterService() + && GlusterFeatureSupported.glusterBrickProvisioning(cluster.getcompatibility_version()); + } + +} diff --git a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/SyncStorageDevicesCommand.java b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/SyncStorageDevicesCommand.java new file mode 100644 index 0000000..da7a4d9 --- /dev/null +++ b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/SyncStorageDevicesCommand.java @@ -0,0 +1,56 @@ +package org.ovirt.engine.core.bll.gluster; + +import java.util.Arrays; + +import org.ovirt.engine.core.bll.VdsCommand; +import org.ovirt.engine.core.bll.VdsValidator; +import org.ovirt.engine.core.bll.utils.Injector; +import org.ovirt.engine.core.common.AuditLogType; +import org.ovirt.engine.core.common.action.VdsActionParameters; +import org.ovirt.engine.core.common.businessentities.VDSGroup; +import org.ovirt.engine.core.common.errors.VdcBllMessages; +import org.ovirt.engine.core.common.gluster.GlusterFeatureSupported; + +public class SyncStorageDevicesCommand<T extends VdsActionParameters> extends VdsCommand<T> { + + public SyncStorageDevicesCommand(T parameters) { + super(parameters); + } + + @Override + protected boolean canDoAction() { + VDSGroup cluster = getVdsGroup(); + if (!cluster.supportsGlusterService() + || !GlusterFeatureSupported.glusterBrickProvisioning(cluster.getcompatibility_version())) { + return failCanDoAction(VdcBllMessages.ACTION_TYPE_FAILED_STORAGE_PROVISIONING_NOT_SUPPORTED_BY_CLUSTER); + } + + VdsValidator validator = new VdsValidator(getVds()); + return validate(validator.isUp()); + } + + @Override + protected void setActionMessageParameters() { + super.setActionMessageParameters(); + addCanDoActionMessage(VdcBllMessages.VAR__ACTION__SYNC); + addCanDoActionMessage(VdcBllMessages.VAR__TYPE__STORAGE_DEVICE); + addCanDoActionMessageVariable("VdsName", getVds().getName()); + } + + @Override + protected void executeCommand() { + + getStorageDeviceSyncJobInstance().refreshStorageDevicesFromServers(Arrays.asList(getVds())); + setSucceeded(true); + } + + private StorageDeviceSyncJob getStorageDeviceSyncJobInstance() { + return Injector.get(StorageDeviceSyncJob.class); + } + + @Override + public AuditLogType getAuditLogTypeValue() { + return getSucceeded() ? AuditLogType.SYNC_STORAGE_DEVICES_IN_HOST + : AuditLogType.SYNC_STORAGE_DEVICES_IN_HOST_FAILED; + } +} diff --git a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/gluster/StorageDeviceSyncJobTest.java b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/gluster/StorageDeviceSyncJobTest.java new file mode 100644 index 0000000..32e38b2 --- /dev/null +++ b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/gluster/StorageDeviceSyncJobTest.java @@ -0,0 +1,232 @@ +package org.ovirt.engine.core.bll.gluster; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.argThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.ovirt.engine.core.utils.MockConfigRule.mockConfig; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentMatcher; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; +import org.mockito.runners.MockitoJUnitRunner; +import org.ovirt.engine.core.bll.utils.ClusterUtils; +import org.ovirt.engine.core.common.businessentities.VDS; +import org.ovirt.engine.core.common.businessentities.VDSGroup; +import org.ovirt.engine.core.common.businessentities.gluster.StorageDevice; +import org.ovirt.engine.core.common.config.ConfigValues; +import org.ovirt.engine.core.common.vdscommands.VDSCommandType; +import org.ovirt.engine.core.common.vdscommands.VDSReturnValue; +import org.ovirt.engine.core.common.vdscommands.VdsIdVDSCommandParametersBase; +import org.ovirt.engine.core.compat.Guid; +import org.ovirt.engine.core.compat.Version; +import org.ovirt.engine.core.dal.dbbroker.auditloghandling.gluster.GlusterAuditLogUtil; +import org.ovirt.engine.core.dao.VdsDAO; +import org.ovirt.engine.core.dao.VdsGroupDAO; +import org.ovirt.engine.core.dao.gluster.StorageDeviceDao; +import org.ovirt.engine.core.utils.MockConfigRule; + +@RunWith(MockitoJUnitRunner.class) +public class StorageDeviceSyncJobTest { + private static final Guid CLUSTER_GUID_3_5 = new Guid("CC111111-1111-1111-1111-111111111111"); + private static final Guid CLUSTER_GUID_3_6 = new Guid("CC111111-1111-1111-1111-111111111111"); + + private static final Guid HOST_ID_WITH_NEW_DEVICES = new Guid("00000000-0000-0000-0000-000000000000"); + private static final Guid HOST_ID_WITH_DEVICES_DELETED = new Guid("00000000-0000-0000-0000-000000000001"); + private static final Guid HOST_ID_WITH_DEVICES_CHANGED = new Guid("00000000-0000-0000-0000-000000000002"); + + private static final Guid DEVICE_WITHOUT_ANYCHANGE = new Guid("00000000-0000-0000-0000-000000000000"); + private static final Guid DEVICE_WITH_CHANGE = new Guid("00000000-0000-0000-0000-000000000001"); + private static final Guid DEVICE_WITH_NAME_CHANGE = new Guid("00000000-0000-0000-0000-000000000002"); + private static final Guid DEVICE_WITH_DEVUUID_BUT_NAME_CHANGED = new Guid("00000000-0000-0000-0000-000000000003"); + + @Mock + private StorageDeviceDao storageDeviceDao; + + @Mock + private ClusterUtils clusterUtils; + + @Mock + private VdsGroupDAO clusterDao; + + @Mock + private VdsDAO vdsDao; + + @Spy + private StorageDeviceSyncJob syncJob; + + @Mock + private GlusterAuditLogUtil logUtil; + @ClassRule + public static MockConfigRule mcr = new MockConfigRule( + mockConfig(ConfigValues.GlusterBrickProvisioningEnabled, Version.v3_5.toString(), true), + mockConfig(ConfigValues.GlusterBrickProvisioningEnabled, Version.v3_4.toString(), false), + mockConfig(ConfigValues.DefaultMinThreadPoolSize, 10), + mockConfig(ConfigValues.DefaultMaxThreadPoolSize, 20), + mockConfig(ConfigValues.DefaultMaxThreadWaitQueueSize, 10) + ); + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + syncJob.setLogUtil(logUtil); + doReturn(storageDeviceDao).when(syncJob).getStorageDeviceDao(); + doReturn(clusterDao).when(syncJob).getClusterDao(); + doReturn(clusterUtils).when(syncJob).getClusterUtils(); + doReturn(getClusters()).when(clusterDao).getAll(); + doReturn(vdsDao).when(syncJob).getVdsDao(); + doReturn(getAllUpServers()).when(clusterUtils).getAllUpServers(CLUSTER_GUID_3_6); + doReturn(getStorageDevices(HOST_ID_WITH_NEW_DEVICES)).when(storageDeviceDao) + .getStorageDevicesInHost(HOST_ID_WITH_NEW_DEVICES); + doReturn(getStorageDevices(HOST_ID_WITH_DEVICES_CHANGED)).when(storageDeviceDao) + .getStorageDevicesInHost(HOST_ID_WITH_DEVICES_CHANGED); + doReturn(getStorageDevices(HOST_ID_WITH_DEVICES_DELETED)).when(storageDeviceDao) + .getStorageDevicesInHost(HOST_ID_WITH_DEVICES_DELETED); + + } + + private List<VDS> getAllUpServers() { + VDS vds1 = new VDS(); + vds1.setId(HOST_ID_WITH_NEW_DEVICES); + VDS vds2 = new VDS(); + vds2.setId(HOST_ID_WITH_DEVICES_CHANGED); + VDS vds3 = new VDS(); + vds3.setId(HOST_ID_WITH_DEVICES_DELETED); + return Arrays.asList(vds1, vds2, vds3); + + } + + private Object getStorageDevicesVDSReturnVal(Guid hostId) { + VDSReturnValue vdsRetValue = new VDSReturnValue(); + vdsRetValue.setSucceeded(true); + if (HOST_ID_WITH_NEW_DEVICES.equals(hostId)) { + vdsRetValue.setReturnValue(Arrays.asList(getStorageDevice("sda", null), + getStorageDevice("sdb", null), + getStorageDevice("sdc", null))); + } else if (HOST_ID_WITH_DEVICES_CHANGED.equals(hostId)) { + List<StorageDevice> devices = new ArrayList<StorageDevice>(); + devices.add(getStorageDevice("device-without-anychange", DEVICE_WITHOUT_ANYCHANGE)); + devices.add(getStorageDevice("new-device-with-name-change", DEVICE_WITH_NAME_CHANGE)); + StorageDevice device = getStorageDevice("device-with-change", DEVICE_WITH_CHANGE); + device.setMountPoint("/temp-mount"); + device.setFsType("XFS"); + device.setSize(12345678L); + devices.add(device); + device = + getStorageDevice("device-with-devuuid-but-name-changed-1", DEVICE_WITH_DEVUUID_BUT_NAME_CHANGED); + device.setDevUuid("123456"); + devices.add(device); + devices.add(getStorageDevice("device-with-devuuid-but-name-changed", null)); + vdsRetValue.setReturnValue(devices); + } + else { + vdsRetValue.setReturnValue(Collections.EMPTY_LIST); + } + return vdsRetValue; + } + + private void mockVdsCommand() { + doReturn(getStorageDevicesVDSReturnVal(HOST_ID_WITH_NEW_DEVICES)).when(syncJob) + .runVdsCommand(eq(VDSCommandType.GetStorageDeviceList), + argThat(isHostMathces(HOST_ID_WITH_NEW_DEVICES))); + + doReturn(getStorageDevicesVDSReturnVal(HOST_ID_WITH_DEVICES_CHANGED)).when(syncJob) + .runVdsCommand(eq(VDSCommandType.GetStorageDeviceList), + argThat(isHostMathces(HOST_ID_WITH_DEVICES_CHANGED))); + + doReturn(getStorageDevicesVDSReturnVal(HOST_ID_WITH_DEVICES_DELETED)).when(syncJob) + .runVdsCommand(eq(VDSCommandType.GetStorageDeviceList), + argThat(isHostMathces(HOST_ID_WITH_DEVICES_DELETED))); + + } + + private ArgumentMatcher<VdsIdVDSCommandParametersBase> isHostMathces(final Guid hostId) { + return new ArgumentMatcher<VdsIdVDSCommandParametersBase>() { + + @Override + public boolean matches(Object argument) { + if (argument instanceof VdsIdVDSCommandParametersBase) { + return hostId.equals(((VdsIdVDSCommandParametersBase) argument).getVdsId()); + } + + return false; + } + }; + } + + @Test + public void testRefreshStorageDevices() { + mockVdsCommand(); + syncJob.refreshStorageDevices(); + Mockito.verify(storageDeviceDao, times(5)).save(any(StorageDevice.class)); + Mockito.verify(storageDeviceDao, times(2)).removeAllInBatch(any(List.class)); + Mockito.verify(storageDeviceDao, times(1)).updateAllInBatch(any(List.class)); + } + + private List<VDSGroup> getClusters() { + List<VDSGroup> list = new ArrayList<>(); + list.add(createCluster(Version.v3_4, CLUSTER_GUID_3_5)); + list.add(createCluster(Version.v3_5, CLUSTER_GUID_3_6)); + return list; + } + + private VDSGroup createCluster(Version v, Guid id) { + VDSGroup cluster = new VDSGroup(); + cluster.setId(id); + cluster.setName("cluster"); + cluster.setGlusterService(true); + cluster.setVirtService(false); + cluster.setcompatibility_version(v); + return cluster; + } + + private StorageDevice getStorageDevice(String name, Guid id) { + StorageDevice storageDevice = new StorageDevice(); + storageDevice.setCanCreateBrick(true); + storageDevice.setDescription("Test Device" + name); + storageDevice.setDevPath("/dev/" + name); + storageDevice.setDevType("SCSI"); + storageDevice.setName(name); + storageDevice.setSize(10000L); + if (id == null) { + storageDevice.setId(Guid.newGuid()); + } else { + storageDevice.setId(id); + } + return storageDevice; + } + + private List<StorageDevice> getStorageDevices(Guid hostId) { + if (HOST_ID_WITH_DEVICES_DELETED.equals(hostId)) { + return Arrays.asList(getStorageDevice("sda", null), + getStorageDevice("sdb", null), + getStorageDevice("sdc", null)); + } else if (HOST_ID_WITH_DEVICES_CHANGED.equals(hostId)) { + List<StorageDevice> deviceList = new ArrayList<StorageDevice>(); + deviceList.add(getStorageDevice("device-without-anychange", DEVICE_WITHOUT_ANYCHANGE)); + deviceList.add(getStorageDevice("device-with-change", DEVICE_WITH_CHANGE)); + deviceList.add(getStorageDevice("device-with-name-change", DEVICE_WITH_NAME_CHANGE)); + StorageDevice device = + getStorageDevice("device-with-devuuid-but-name-changed", DEVICE_WITH_DEVUUID_BUT_NAME_CHANGED); + device.setDevUuid("123456"); + device.setSize(999999L); + deviceList.add(device); + return deviceList; + } else { + return Collections.emptyList(); + } + } + +} diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java index 70a7981..20c2170 100644 --- a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/AuditLogType.java @@ -415,6 +415,11 @@ GLUSTER_VOLUME_SNAPSHOT_CONFIG_UPDATED(4121), GLUSTER_VOLUME_SNAPSHOT_CONFIG_UPDATE_FAILED(4122, AuditLogSeverity.ERROR), GLUSTER_VOLUME_SNAPSHOT_CONFIG_UPDATE_FAILED_PARTIALLY(4123, AuditLogSeverity.ERROR), + NEW_STORAGE_DEVICE_DETECTED(4124), + STORAGE_DEVICE_REMOVED_FROM_THE_HOST(4125), + SYNC_STORAGE_DEVICES_IN_HOST(4126), + SYNC_STORAGE_DEVICES_IN_HOST_FAILED(4127), + USER_FORCE_SELECTED_SPM(159), USER_VDS_RESTART(41), USER_FAILED_VDS_RESTART(107, AuditLogSeverity.ERROR), diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java index 8909659..1a45d4d 100644 --- a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/action/VdcActionType.java @@ -318,6 +318,7 @@ DeactivateGlusterVolumeSnapshot(1437, ActionGroup.MANIPULATE_GLUSTER_VOLUME, QuotaDependency.NONE), RestoreGlusterVolumeSnapshot(1438, ActionGroup.MANIPULATE_GLUSTER_VOLUME, QuotaDependency.NONE), UpdateGlusterVolumeSnapshotConfig(1439, ActionGroup.MANIPULATE_GLUSTER_VOLUME, QuotaDependency.NONE), + SyncStorageDevices(1440, ActionGroup.MANIPULATE_HOST, QuotaDependency.NONE), // Cluster Policy AddClusterPolicy(1450, ActionGroup.EDIT_STORAGE_POOL_CONFIGURATION, false, QuotaDependency.NONE), diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/config/ConfigValues.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/config/ConfigValues.java index 27cef6c..63a9a51 100644 --- a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/config/ConfigValues.java +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/config/ConfigValues.java @@ -1301,6 +1301,13 @@ GlusterRefreshRateLight, /** + * Refresh rate (in seconds) for Storage Devices. + */ + @TypeConverterAttribute(Integer.class) + @DefaultValueAttribute("7200") + GlusterRefreshRateStorageDevices, + + /** * Refresh rate (in seconds) for heavy-weight gluster data i.e. commands to fetch such data adds a considerable * overhead on the GlusterFS processes. */ @@ -1453,6 +1460,10 @@ @DefaultValueAttribute("true") GlusterVolumeSnapshotSupported, + @TypeConverterAttribute(Boolean.class) + @DefaultValueAttribute("true") + GlusterBrickProvisioningEnabled, + @TypeConverterAttribute(Integer.class) @DefaultValueAttribute("300") GlusterRefreshRateSnapshotDiscovery, diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java index 2fb6526..f08f2fe 100644 --- a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/errors/VdcBllMessages.java @@ -51,6 +51,7 @@ VAR__TYPE__GLUSTER_GEOREP_SESSION, VAR__TYPE__GLUSTER_GEOREP_CONFIG, VAR__TYPE__GLUSTER_VOLUME_SNAPSHOT, + VAR__TYPE__STORAGE_DEVICE, // External Event VAR__TYPE__EXTERNAL_EVENT, @@ -113,6 +114,7 @@ VAR__ACTION__UPDATE_SLA_POLICY, VAR__ACTION__UPDATE_VM_VERSION, VAR__ACTION__VOLUME_SNAPSHOT_CONFIG_UPDATE, + VAR__ACTION__SYNC, // Host statuses replacements VAR__HOST_STATUS__UP, @@ -955,6 +957,7 @@ ACTION_TYPE_FAILED_GLUSTER_VOLUME_SNAPSHOT_ALREADY_ACTIVATED(ErrorType.CONFLICT), ACTION_TYPE_FAILED_GLUSTER_VOLUME_SNAPSHOT_ALREADY_DEACTIVATED(ErrorType.CONFLICT), GLUSTER_TASKS_NOT_SUPPORTED_FOR_CLUSTER_LEVEL(ErrorType.INCOMPATIBLE_VERSION), + ACTION_TYPE_FAILED_STORAGE_PROVISIONING_NOT_SUPPORTED_BY_CLUSTER(ErrorType.NOT_SUPPORTED), // OpenStack Glance ACTION_TYPE_FAILED_IMAGE_DOWNLOAD_ERROR(ErrorType.BAD_PARAMETERS), diff --git a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/gluster/GlusterFeatureSupported.java b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/gluster/GlusterFeatureSupported.java index faab9c6..d08bcd2 100644 --- a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/gluster/GlusterFeatureSupported.java +++ b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/gluster/GlusterFeatureSupported.java @@ -101,4 +101,15 @@ public static boolean glusterSnapshot(Version version) { return supportedInConfig(ConfigValues.GlusterVolumeSnapshotSupported, version); } + + /** + * + * @param version + * Compatibility version to check for. + * @return <code>true</code> if disk provisioning feature is enabled, + * <code>false</code> if it's not. + */ + public static boolean glusterBrickProvisioning(Version version) { + return supportedInConfig(ConfigValues.GlusterBrickProvisioningEnabled, version); + } } diff --git a/backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties b/backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties index 7bd5435..c361745 100644 --- a/backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties +++ b/backend/manager/modules/dal/src/main/resources/bundles/AppErrors.properties @@ -368,6 +368,7 @@ VAR__ACTION__REMOVE_BRICKS_COMMIT=$action commit removing VAR__ACTION__START_PROFILE=$action start profiling VAR__ACTION__STOP_PROFILE=$action stop profiling +VAR__ACTION__SYNC=$action sync VAR__ACTION__ENABLE=$action enable VAR__ACTION__DISABLE=$action disable VAR__ACTION__REFRESH=$action refresh @@ -1038,6 +1039,7 @@ VAR__TYPE__GLUSTER_SERVICE=$type Service VAR__TYPE__GLUSTER_GEOREP_SESSION=$type Geo-replication session VAR__TYPE__GLUSTER_VOLUME_SNAPSHOT=$type Gluster Volume Snapshot +VAR__TYPE__STORAGE_DEVICE=$type Storage Device VALIDATION.GLUSTER.VOLUME.ID.NOT_NULL=Volume ID is required. VALIDATION.GLUSTER.VOLUME.CLUSTER_ID.NOT_NULL=Cluster ID is required. VALIDATION.GLUSTER.VOLUME.NAME.NOT_NULL=Volume Name is required. @@ -1157,6 +1159,7 @@ ACTION_TYPE_FAILED_GLUSTER_VOLUME_SNAPSHOT_ALREADY_ACTIVATED=Cannot ${action} ${type}. Gluster volume snapshot ${snapname} is already activated. ACTION_TYPE_FAILED_GLUSTER_VOLUME_SNAPSHOT_ALREADY_DEACTIVATED=Cannot ${action} ${type}. Gluster volume snapshot ${snapname} is already de-activated. GLUSTER_TASKS_NOT_SUPPORTED_FOR_CLUSTER_LEVEL=Cannot ${action} ${type}. Gluster task management is not supported in compatibility version ${compatibilityVersion}. +ACTION_TYPE_FAILED_STORAGE_PROVISIONING_NOT_SUPPORTED_BY_CLUSTER=Cannot ${action} ${type}. The selected cluster doesn't support Storage provisioning. ACTION_TYPE_FAILED_TAG_ID_REQUIRED=Cannot ${action} ${type}. Tag ID is required. ACTION_TYPE_FAILED_QOS_OUT_OF_RANGE_VALUES=Cannot ${action} ${type}. Values are out of range. diff --git a/backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties b/backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties index 7f2b178..266129e 100644 --- a/backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties +++ b/backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties @@ -837,6 +837,10 @@ GLUSTER_VOLUME_SNAPSHOT_CONFIG_UPDATED=Updated Gluster volume snapshot configuration(s). GLUSTER_VOLUME_SNAPSHOT_CONFIG_UPDATE_FAILED=Failed to update gluster volume snapshot configuration(s). GLUSTER_VOLUME_SNAPSHOT_CONFIG_UPDATE_FAILED_PARTIALLY=Failed to update gluster volume snapshot configuration(s) ${failedSnapshotConfigs}. +NEW_STORAGE_DEVICE_DETECTED=Found new storage device ${storageDevice} on host ${VdsName}, and added it to engine DB." +STORAGE_DEVICE_REMOVED_FROM_THE_HOST=Detected deletion of storage device ${storageDevice} on host ${VdsName}, and deleting it from engine DB." +SYNC_STORAGE_DEVICES_IN_HOST=Manually synced the storage devices from host ${VdsName} +SYNC_STORAGE_DEVICES_IN_HOST_FAILED=Failed to synced storage devices from host ${VdsName} VDS_UNTRUSTED=Host ${VdsName} was set to non-operational. Host is not trusted by the attestation service. USER_ADDED_NETWORK_QOS=Network QoS ${QosName} was added. (User: ${UserName}) USER_FAILED_TO_ADD_NETWORK_QOS=Failed to add Network QoS ${QosName}. (User: ${UserName}) diff --git a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java index dfddda1..c580a7f 100644 --- a/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java +++ b/frontend/webadmin/modules/frontend/src/main/java/org/ovirt/engine/ui/frontend/AppErrors.java @@ -1009,6 +1009,9 @@ @DefaultStringValue("$action commit removing") String VAR__ACTION__REMOVE_BRICKS_COMMIT(); + @DefaultStringValue("$action sync") + String VAR__ACTION__SYNC(); + @DefaultStringValue("$action start profiling") String VAR__ACTION__START_PROFILE(); @@ -1116,6 +1119,9 @@ @DefaultStringValue("$type Service") String VAR__TYPE__GLUSTER_SERVICE(); + + @DefaultStringValue("$type Storage Device") + String VAR__TYPE__STORAGE_DEVICE(); @DefaultStringValue("Cannot ${action} ${type}. The chosen disk drive letter is already in use, please select a free one.") String ACTION_TYPE_FAILED_DISK_LETTER_ALREADY_IN_USE(); @@ -3128,6 +3134,9 @@ @DefaultStringValue("Cannot ${action} ${type}. Gluster task management is not supported in compatibility version ${compatibilityVersion}.") String GLUSTER_TASKS_NOT_SUPPORTED_FOR_CLUSTER_LEVEL(); + @DefaultStringValue("Cannot ${action} ${type}. The selected cluster doesn't support Storage provisioning.") + String ACTION_TYPE_FAILED_STORAGE_PROVISIONING_NOT_SUPPORTED_BY_CLUSTER(); + @DefaultStringValue("Cannot ${action} ${type}. All three values are needed in order to define QoS on each network directions.") String ACTION_TYPE_FAILED_NETWORK_QOS_MISSING_VALUES(); diff --git a/packaging/dbscripts/upgrade/pre_upgrade/0000_config.sql b/packaging/dbscripts/upgrade/pre_upgrade/0000_config.sql index 1907c10..54a91ec 100644 --- a/packaging/dbscripts/upgrade/pre_upgrade/0000_config.sql +++ b/packaging/dbscripts/upgrade/pre_upgrade/0000_config.sql @@ -167,6 +167,7 @@ select fn_db_add_config_value('GlusterServicesEnabled', 'false', '3.0'); select fn_db_add_config_value('GlusterServicesEnabled', 'false', '3.1'); select fn_db_add_config_value('GlusterServicesEnabled', 'false', '3.2'); +select fn_db_add_config_value('GlusterRefreshRateStorageDevices', '7200', 'general'); select fn_db_add_config_value('GlusterSupport', 'false', '3.0'); select fn_db_add_config_value('GlusterSupportForceCreateVolume', 'false', '3.0'); select fn_db_add_config_value('GlusterSupportForceCreateVolume', 'false', '3.1'); @@ -202,6 +203,14 @@ select fn_db_add_config_value('GlusterRefreshRateGeoRepStatusInSecs', '300', 'general'); +-- Gluster Disk Provisioning -- +select fn_db_add_config_value('GlusterBrickProvisioningEnabled', 'false', '3.0'); +select fn_db_add_config_value('GlusterBrickProvisioningEnabled', 'false', '3.1'); +select fn_db_add_config_value('GlusterBrickProvisioningEnabled', 'false', '3.2'); +select fn_db_add_config_value('GlusterBrickProvisioningEnabled', 'false', '3.3'); +select fn_db_add_config_value('GlusterBrickProvisioningEnabled', 'false', '3.4'); +select fn_db_add_config_value('GlusterBrickProvisioningEnabled', 'false', '3.5'); + -- OpenStack related select fn_db_add_config_value('KeystoneAuthUrl', '', 'general'); -- To view, visit https://gerrit.ovirt.org/39705 To unsubscribe, visit https://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I651bb51873a96d491c5a5f51147cb72be958985a Gerrit-PatchSet: 1 Gerrit-Project: ovirt-engine Gerrit-Branch: ovirt-engine-3.5-gluster Gerrit-Owner: Ramesh N <[email protected]> _______________________________________________ Engine-patches mailing list [email protected] http://lists.ovirt.org/mailman/listinfo/engine-patches
