package org.ovirt.engine.core.dao.gluster; import java.util.Collection; import java.util.HashSet; import java.util.List; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Singleton; import org.apache.commons.lang.StringUtils; import org.ovirt.engine.core.common.asynctasks.gluster.GlusterAsyncTask; import org.ovirt.engine.core.common.asynctasks.gluster.GlusterTaskType; import org.ovirt.engine.core.common.businessentities.gluster.AccessProtocol; import org.ovirt.engine.core.common.businessentities.gluster.GlusterBrickEntity; import org.ovirt.engine.core.common.businessentities.gluster.GlusterStatus; import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeAdvancedDetails; import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity; import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeOptionEntity; import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeSizeInfo; import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeSnapshotConfig; import org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeType; import org.ovirt.engine.core.common.businessentities.gluster.TransportType; import org.ovirt.engine.core.common.constants.gluster.GlusterConstants; import org.ovirt.engine.core.common.job.JobExecutionStatus; import org.ovirt.engine.core.common.job.StepEnum; import org.ovirt.engine.core.common.utils.EnumUtils; import org.ovirt.engine.core.compat.Guid; import org.ovirt.engine.core.dao.MassOperationsGenericDao; import org.springframework.jdbc.core.RowMapper; import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; /** * Implementation of the DB Facade for Gluster Volumes. */ @Named @Singleton public class GlusterVolumeDaoImpl extends MassOperationsGenericDao<GlusterVolumeEntity, Guid> implements GlusterVolumeDao { private static final RowMapper<GlusterVolumeEntity> volumeRowMapper = (rs, rowNum) -> { GlusterVolumeEntity entity = new GlusterVolumeEntity(); entity.setId(getGuidDefaultEmpty(rs, "id")); entity.setClusterId(getGuidDefaultEmpty(rs, "cluster_id")); entity.setClusterName(rs.getString("cluster_name")); entity.setName(rs.getString("vol_name")); entity.setVolumeType(GlusterVolumeType.valueOf(rs.getString("vol_type"))); entity.setStatus(GlusterStatus.valueOf(rs.getString("status"))); entity.setReplicaCount(rs.getInt("replica_count")); entity.setStripeCount(rs.getInt("stripe_count")); entity.setDisperseCount(rs.getInt("disperse_count")); entity.setRedundancyCount(rs.getInt("redundancy_count")); entity.setSnapshotsCount(rs.getInt("snapshot_count")); entity.setSnapshotScheduled(rs.getBoolean("snapshot_scheduled")); entity.setIsGeoRepMaster(rs.getBoolean("is_master")); entity.setGeoRepMasterVolAndClusterName(rs.getString("master_vol_cluster")); entity.setIsArbiter(rs.getBoolean("is_arbiter")); return entity; }; private static final RowMapper<AccessProtocol> accessProtocolRowMapper = (rs, rowNum) -> AccessProtocol.valueOf(rs.getString("access_protocol")); private static final RowMapper<TransportType> transportTypeRowMapper = (rs, rowNum) -> TransportType.valueOf(rs.getString("transport_type")); private static final RowMapper<GlusterAsyncTask> glusterAsyncTaskRowMapper = (rs, rowNum) -> { GlusterAsyncTask asyncTask = new GlusterAsyncTask(); asyncTask.setTaskId(getGuid(rs, "external_id")); String jobStatus = rs.getString("job_status"); if (asyncTask.getTaskId() != null || JobExecutionStatus.STARTED.name().equalsIgnoreCase(jobStatus)) { asyncTask.setJobId(getGuid(rs, "job_job_id")); asyncTask.setJobStatus(JobExecutionStatus.valueOf(jobStatus)); } String stepStatus = rs.getString("status"); String stepType = rs.getString("step_type"); if (stepType != null && !stepType.isEmpty()) { asyncTask.setType(GlusterTaskType.forValue(StepEnum.valueOf(stepType))); } if (stepStatus != null && !stepStatus.isEmpty()) { asyncTask.setStatus(JobExecutionStatus.valueOf(stepStatus)); } return asyncTask; }; private static final RowMapper<GlusterVolumeAdvancedDetails> glusterVolumesAdvancedDetailsRowMapper = (rs, rowNum) -> { GlusterVolumeAdvancedDetails advancedDetails = new GlusterVolumeAdvancedDetails(); GlusterVolumeSizeInfo capacityInfo = new GlusterVolumeSizeInfo(); capacityInfo.setVolumeId(getGuid(rs, "volume_id")); capacityInfo.setTotalSize(rs.getLong("total_space")); capacityInfo.setUsedSize(rs.getLong("used_space")); capacityInfo.setFreeSize(rs.getLong("free_space")); advancedDetails.setUpdatedAt(rs.getTimestamp("_update_date")); advancedDetails.setCapacityInfo(capacityInfo); return advancedDetails; }; @Inject private GlusterOptionDao glusterOptionDao; @Inject private GlusterBrickDao glusterBrickDao; @Inject private GlusterVolumeSnapshotConfigDao glusterVolumeSnapshotConfigDao; public GlusterVolumeDaoImpl() { super("GlusterVolume"); setProcedureNameForGet("GetGlusterVolumeById"); } @Override public void save(GlusterVolumeEntity volume) { insertVolumeEntity(volume); insertVolumeBricks(volume); insertVolumeOptions(volume); insertVolumeAccessProtocols(volume); insertVolumeTransportTypes(volume); } @Override public GlusterVolumeEntity getById(Guid id) { GlusterVolumeEntity volume = getCallsHandler().executeRead( "GetGlusterVolumeById", volumeRowMapper, createVolumeIdParams(id)); fetchRelatedEntities(volume); return volume; } @Override public GlusterVolumeEntity getByName(Guid clusterId, String volName) { GlusterVolumeEntity volume = getCallsHandler().executeRead( "GetGlusterVolumeByName", volumeRowMapper, getCustomMapSqlParameterSource() .addValue("cluster_id", clusterId) .addValue("vol_name", volName)); fetchRelatedEntities(volume); return volume; } @Override public List<GlusterVolumeEntity> getByClusterId(Guid clusterId) { List<GlusterVolumeEntity> volumes = getCallsHandler().executeReadList("GetGlusterVolumesByClusterGuid", volumeRowMapper, getCustomMapSqlParameterSource().addValue("cluster_id", clusterId)); fetchRelatedEntities(volumes); return volumes; } @Override public List<GlusterVolumeEntity> getVolumesByOption(Guid clusterId, GlusterStatus status, String optionKey, String optionValue) { List<GlusterVolumeEntity> volumes = getCallsHandler().executeReadList("GetGlusterVolumesByOption", volumeRowMapper, getCustomMapSqlParameterSource() .addValue("cluster_id", clusterId) .addValue("status", EnumUtils.nameOrNull(status)) .addValue("option_key", optionKey) .addValue("option_val", optionValue)); fetchRelatedEntities(volumes); return volumes; } @Override public List<GlusterVolumeEntity> getVolumesByStatusTypesAndOption(Guid clusterId, GlusterStatus status, List<GlusterVolumeType> volumeTypes, String optionKey, String optionValue) { List<GlusterVolumeEntity> volumes = getCallsHandler().executeReadList("GetGlusterVolumesByStatusTypesAndOption", volumeRowMapper, getCustomMapSqlParameterSource() .addValue("cluster_id", clusterId) .addValue("status", EnumUtils.nameOrNull(status)) .addValue("vol_types", StringUtils.join(volumeTypes, ',')) .addValue("option_key", optionKey) .addValue("option_val", optionValue)); fetchRelatedEntities(volumes); return volumes; } @Override public List<GlusterVolumeEntity> getVolumesByStatusAndTypes(Guid clusterId, GlusterStatus status, List<GlusterVolumeType> volumeTypes) { List<GlusterVolumeEntity> volumes = getCallsHandler().executeReadList("GetGlusterVolumesByStatusAndTypes", volumeRowMapper, getCustomMapSqlParameterSource() .addValue("cluster_id", clusterId) .addValue("status", EnumUtils.nameOrNull(status)) .addValue("vol_types", StringUtils.join(volumeTypes, ','))); fetchRelatedEntities(volumes); return volumes; } @Override public List<GlusterVolumeEntity> getVolumesSupportedAsStorageDomain() { List<GlusterVolumeEntity> volumes = getCallsHandler().executeReadList("GetGlusterVolumesSupportedAsStorageDomain", volumeRowMapper, null); fetchRelatedEntities(volumes); return volumes; } @Override public List<GlusterVolumeEntity> getAllWithQuery(String query) { List<GlusterVolumeEntity> volumes = getJdbcTemplate().query(query, volumeRowMapper); fetchRelatedEntities(volumes); return volumes; } @Override public void remove(Guid id) { getCallsHandler().executeModification("DeleteGlusterVolumeByGuid", createVolumeIdParams(id)); } @Override public void removeByName(Guid clusterId, String volName) { getCallsHandler().executeModification("DeleteGlusterVolumeByName", getCustomMapSqlParameterSource() .addValue("cluster_id", clusterId) .addValue("vol_name", volName)); } @Override public void removeAll(Collection<Guid> ids) { getCallsHandler().executeModification("DeleteGlusterVolumesByGuids", getCustomMapSqlParameterSource().addValue("volume_ids", StringUtils.join(ids, ','))); } @Override public void removeByClusterId(Guid clusterId) { getCallsHandler().executeModification("DeleteGlusterVolumesByClusterId", getCustomMapSqlParameterSource() .addValue("cluster_id", clusterId)); } @Override public void updateVolumeStatus(Guid volumeId, GlusterStatus status) { getCallsHandler().executeModification("UpdateGlusterVolumeStatus", createVolumeIdParams(volumeId).addValue("status", EnumUtils.nameOrNull(status))); } @Override public void updateVolumeTask(Guid volumeId, Guid taskId) { getCallsHandler().executeModification("UpdateGlusterVolumeAsyncTask", createVolumeIdParams(volumeId).addValue("task_id", taskId)); } @Override public GlusterVolumeEntity getVolumeByGlusterTask(Guid taskId) { GlusterVolumeEntity volume = getCallsHandler().executeRead( "GetGlusterVolumeByGlusterTaskId", volumeRowMapper, getCustomMapSqlParameterSource().addValue("task_id", taskId)); fetchRelatedEntities(volume); return volume; } @Override public void updateVolumeStatusByName(Guid clusterId, String volumeName, GlusterStatus status) { getCallsHandler().executeModification("UpdateGlusterVolumeStatusByName", getCustomMapSqlParameterSource() .addValue("cluster_id", clusterId) .addValue("vol_name", volumeName) .addValue("status", EnumUtils.nameOrNull(status))); } @Override public void addAccessProtocol(Guid volumeId, AccessProtocol protocol) { getCallsHandler().executeModification("InsertGlusterVolumeAccessProtocol", createAccessProtocolParams(volumeId, protocol)); } @Override public void removeAccessProtocol(Guid volumeId, AccessProtocol protocol) { getCallsHandler().executeModification("DeleteGlusterVolumeAccessProtocol", createAccessProtocolParams(volumeId, protocol)); } @Override public void addTransportType(Guid volumeId, TransportType transportType) { getCallsHandler().executeModification("InsertGlusterVolumeTransportType", createTransportTypeParams(volumeId, transportType)); } @Override public void removeTransportType(Guid volumeId, TransportType transportType) { getCallsHandler().executeModification("DeleteGlusterVolumeTransportType", createTransportTypeParams(volumeId, transportType)); } private List<AccessProtocol> getAccessProtocolsOfVolume(Guid volumeId) { return getCallsHandler().executeReadList( "GetAccessProtocolsByGlusterVolumeGuid", accessProtocolRowMapper, createVolumeIdParams(volumeId)); } private List<TransportType> getTransportTypesOfVolume(Guid volumeId) { return getCallsHandler().executeReadList( "GetTransportTypesByGlusterVolumeGuid", transportTypeRowMapper, createVolumeIdParams(volumeId)); } private GlusterAsyncTask getAsyncTaskOfVolume(Guid volumeId) { List<GlusterAsyncTask> glusterAsyncTasks = getCallsHandler().executeReadList( "GetGlusterTaskByGlusterVolumeGuid", glusterAsyncTaskRowMapper, createVolumeIdParams(volumeId)); if(glusterAsyncTasks != null && !glusterAsyncTasks.isEmpty()) { return glusterAsyncTasks.get(0); } return null; } private MapSqlParameterSource createVolumeIdParams(Guid id) { return getCustomMapSqlParameterSource().addValue("volume_id", id); } private MapSqlParameterSource createAccessProtocolParams(Guid volumeId, AccessProtocol protocol) { return createVolumeIdParams(volumeId).addValue("access_protocol", EnumUtils.nameOrNull(protocol)); } private MapSqlParameterSource createTransportTypeParams(Guid volumeId, TransportType transportType) { return createVolumeIdParams(volumeId).addValue("transport_type", EnumUtils.nameOrNull(transportType)); } private void insertVolumeEntity(GlusterVolumeEntity volume) { getCallsHandler().executeModification("InsertGlusterVolume", createFullParametersMapper(volume)); } private void insertVolumeBricks(GlusterVolumeEntity volume) { List<GlusterBrickEntity> bricks = volume.getBricks(); for (GlusterBrickEntity brick : bricks) { if (brick.getVolumeId() == null) { brick.setVolumeId(volume.getId()); } glusterBrickDao.save(brick); } } private void insertVolumeOptions(GlusterVolumeEntity volume) { Collection<GlusterVolumeOptionEntity> options = volume.getOptions(); for (GlusterVolumeOptionEntity option : options) { if (option.getVolumeId() == null) { option.setVolumeId(volume.getId()); } glusterOptionDao.save(option); } } private void insertVolumeAccessProtocols(GlusterVolumeEntity volume) { for (AccessProtocol protocol : volume.getAccessProtocols()) { addAccessProtocol(volume.getId(), protocol); } } private void insertVolumeTransportTypes(GlusterVolumeEntity volume) { for (TransportType transportType : volume.getTransportTypes()) { addTransportType(volume.getId(), transportType); } } /** * Fetches and populates related entities like bricks, options, access protocols for the given volumes */ private void fetchRelatedEntities(List<GlusterVolumeEntity> volumes) { volumes.forEach(this::fetchRelatedEntities); } /** * Fetches and populates related entities like bricks, options, access protocols for the given volume */ private void fetchRelatedEntities(GlusterVolumeEntity volume) { if (volume != null) { volume.setOptions(glusterOptionDao.getOptionsOfVolume(volume.getId())); volume.setAccessProtocols(new HashSet<>(getAccessProtocolsOfVolume(volume.getId()))); volume.setTransportTypes(new HashSet<>(getTransportTypesOfVolume(volume.getId()))); GlusterVolumeAdvancedDetails advancedDetails = fetchAdvancedDatails(volume.getId()); if (advancedDetails != null) { volume.setAdvancedDetails(advancedDetails); } GlusterAsyncTask asyncTask = getAsyncTaskOfVolume(volume.getId()); if (asyncTask != null) { volume.setAsyncTask(asyncTask); } List<GlusterBrickEntity> bricks = glusterBrickDao.getBricksOfVolume(volume.getId()); if (volume.getAsyncTask() != null && volume.getAsyncTask().getTaskId() != null) { bricks.stream() .filter(brick -> brick.getAsyncTask() != null && brick.getAsyncTask().getTaskId() != null && brick.getAsyncTask().getTaskId().equals(volume.getAsyncTask().getTaskId())) .forEach(brick -> brick.setAsyncTask(volume.getAsyncTask())); } volume.setBricks(bricks); GlusterVolumeSnapshotConfig config = glusterVolumeSnapshotConfigDao .getConfigByVolumeIdAndName(volume.getClusterId(), volume.getId(), GlusterConstants.VOLUME_SNAPSHOT_MAX_HARD_LIMIT); if (config == null || StringUtils.isEmpty(config.getParamValue())) { config = glusterVolumeSnapshotConfigDao .getConfigByClusterIdAndName(volume.getClusterId(), GlusterConstants.VOLUME_SNAPSHOT_MAX_HARD_LIMIT); } volume.setSnapMaxLimit(config != null ? Integer.parseInt(config.getParamValue()) : 0); } } private GlusterVolumeAdvancedDetails fetchAdvancedDatails(Guid volumeId) { return getCallsHandler().executeRead( "GetGlusterVolumeDetailsByID", glusterVolumesAdvancedDetailsRowMapper, createVolumeIdParams(volumeId)); } private MapSqlParameterSource createReplicaCountParams(Guid volumeId, int replicaCount) { return createVolumeIdParams(volumeId).addValue("replica_count", replicaCount); } @Override public void updateReplicaCount(Guid volumeId, int replicaCount) { getCallsHandler().executeModification("UpdateReplicaCount", createReplicaCountParams(volumeId, replicaCount)); } @Override public void updateGlusterVolume(GlusterVolumeEntity volume) { getCallsHandler().executeModification("UpdateGlusterVolume", getCustomMapSqlParameterSource() .addValue("id", volume.getId()) .addValue("cluster_id", volume.getClusterId()) .addValue("vol_name", volume.getName()) .addValue("vol_type", EnumUtils.nameOrNull(volume.getVolumeType())) .addValue("status", EnumUtils.nameOrNull(volume.getStatus())) .addValue("replica_count", volume.getReplicaCount()) .addValue("stripe_count", volume.getStripeCount()) .addValue("disperse_count", volume.getDisperseCount()) .addValue("redundancy_count", volume.getRedundancyCount()) .addValue("is_arbiter", volume.getIsArbiter())); } @Override public void updateVolumeCapacityInfo(GlusterVolumeSizeInfo volumeCapacityInfo) { getCallsHandler().executeModification("UpdateGlusterVolumeDetails", createCapacityInfoParas(volumeCapacityInfo)); } @Override public void addVolumeCapacityInfo(GlusterVolumeSizeInfo volumeCapacityInfo) { getCallsHandler().executeModification("InsertGlusterVolumeDetails", createCapacityInfoParas(volumeCapacityInfo)); } private MapSqlParameterSource createCapacityInfoParas(GlusterVolumeSizeInfo volumeCapacityInfo) { return getCustomMapSqlParameterSource() .addValue("volume_id", volumeCapacityInfo.getVolumeId()) .addValue("total_space", volumeCapacityInfo.getTotalSize()) .addValue("used_space", volumeCapacityInfo.getUsedSize()) .addValue("free_space", volumeCapacityInfo.getFreeSize()); } @Override protected MapSqlParameterSource createFullParametersMapper(GlusterVolumeEntity volume) { return getCustomMapSqlParameterSource() .addValue("id", volume.getId()) .addValue("cluster_id", volume.getClusterId()) .addValue("vol_name", volume.getName()) .addValue("vol_type", EnumUtils.nameOrNull(volume.getVolumeType())) .addValue("status", EnumUtils.nameOrNull(volume.getStatus())) .addValue("replica_count", volume.getReplicaCount()) .addValue("stripe_count", volume.getStripeCount()) .addValue("disperse_count", volume.getDisperseCount()) .addValue("redundancy_count", volume.getRedundancyCount()) .addValue("is_arbiter", volume.getIsArbiter()); } @Override protected MapSqlParameterSource createIdParameterMapper(Guid id) { return createVolumeIdParams(id); } @Override protected RowMapper<GlusterVolumeEntity> createEntityRowMapper() { return volumeRowMapper; } @Override public void addTransportTypes(Guid volumeId, Collection<TransportType> transportTypes) { for (TransportType transportType : transportTypes) { addTransportType(volumeId, transportType); } } @Override public void removeTransportTypes(Guid volumeId, Collection<TransportType> transportTypes) { for (TransportType transportType : transportTypes) { removeTransportType(volumeId, transportType); } } }