Sahina Bose has uploaded a new change for review.

Change subject: engine: Geo-rep monitoring
......................................................................

engine: Geo-rep monitoring

Monitoring details of geo rep sessions - detects
new sessions and updates the database
Consolidates the session status based on individual
node status
Removes sessions from database if deleted from CLI
Corrected errors with wrong session id while retrieving
from VDS and status while saving to DB.

Change-Id: I3304addda17cf49eee93f311e043b0e15212cd91
Bug-Url: https://bugzilla.redhat.com/1138116
Signed-off-by: Sahina Bose <[email protected]>
---
A 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterGeoRepSyncJob.java
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/test/java/org/ovirt/engine/core/bll/gluster/GlusterGeoRepSyncJobTest.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/config/ConfigValues.java
M 
backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/gluster/GlusterFeatureSupported.java
M 
backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDao.java
M 
backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDaoDbFacadeImpl.java
M 
backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties
M 
backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDaoTest.java
M 
backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/gluster/GlusterVolumeGeoRepStatusForXmlRpc.java
M packaging/dbscripts/gluster_georep_sp.sql
A packaging/dbscripts/upgrade/03_05_1270_add_idx_gluster_georep_slavevolname.sql
M packaging/dbscripts/upgrade/pre_upgrade/0000_config.sql
15 files changed, 563 insertions(+), 8 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/74/39574/1

diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterGeoRepSyncJob.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterGeoRepSyncJob.java
new file mode 100644
index 0000000..362fb3f
--- /dev/null
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/gluster/GlusterGeoRepSyncJob.java
@@ -0,0 +1,233 @@
+package org.ovirt.engine.core.bll.gluster;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.ArrayUtils;
+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.GeoRepSessionStatus;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterGeoRepSession;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterGeoRepSessionDetails;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity;
+import org.ovirt.engine.core.common.constants.gluster.GlusterConstants;
+import org.ovirt.engine.core.common.gluster.GlusterFeatureSupported;
+import org.ovirt.engine.core.common.vdscommands.VDSCommandType;
+import org.ovirt.engine.core.common.vdscommands.VDSReturnValue;
+import 
org.ovirt.engine.core.common.vdscommands.gluster.GlusterVolumeGeoRepSessionVDSParameters;
+import org.ovirt.engine.core.compat.Guid;
+import org.ovirt.engine.core.utils.timer.OnTimerMethodAnnotation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GlusterGeoRepSyncJob extends GlusterJob {
+    private static final Logger log = 
LoggerFactory.getLogger(GlusterGeoRepSyncJob.class);
+
+    private static final GlusterGeoRepSyncJob instance = new 
GlusterGeoRepSyncJob();
+    private static final GeoRepSessionStatus[] overridableStatuses = { 
GeoRepSessionStatus.ACTIVE,
+            GeoRepSessionStatus.INITIALIZING,
+            GeoRepSessionStatus.NOTSTARTED
+    };
+
+    public void init() {
+        log.info("Gluster georeplication monitoring has been initialized");
+    }
+
+    public static GlusterGeoRepSyncJob getInstance() {
+        return instance;
+    }
+
+    @OnTimerMethodAnnotation("gluster_georep_poll_event")
+    public void refreshGeoRepData() {
+        // get all clusters
+        List<VDSGroup> clusters = getClusterDao().getAll();
+        // for every cluster that supports geo-rep monitoring
+        for (VDSGroup cluster : clusters) {
+            refreshGeoRepDataInCluster(cluster);
+        }
+
+    }
+
+    public void refreshGeoRepDataInCluster(VDSGroup cluster) {
+        if (!supportsGlusterGeoRepFeature(cluster)) {
+            return;
+        }
+
+        Map<String, GlusterGeoRepSession> sessionsMap = 
getSessionsForCluster(cluster);
+        if (sessionsMap == null) {
+            log.debug("Error in retrieving sessions for cluster '{}' from CLI, 
nothing to do", cluster.getName());
+            return;
+        }
+
+        removeDeletedSessions(cluster.getId(), sessionsMap);
+
+        // for each geo-rep session, find session in database and update 
details.
+        for (GlusterGeoRepSession session : sessionsMap.values()) {
+            GlusterVolumeEntity masterVolume = getVolume(cluster, 
session.getMasterVolumeName());
+            if (masterVolume == null) {
+                log.info("Could not find corresponding volume for geo-rep 
session '{}' and volume '{}' - status will not be updated.",
+                        session.getSessionKey(),
+                        session.getMasterVolumeName());
+            } else {
+                session.setMasterVolumeId(masterVolume.getId());
+                // update consolidated status
+                updateGeoRepStatus(masterVolume, session);
+            }
+
+            // check if session exists in database
+            GlusterGeoRepSession sessionInDb = 
getGeoRepDao().getGeoRepSession(session.getSessionKey());
+            if (sessionInDb == null) {
+                // save the session in database first.
+                log.debug("detected new geo-rep session '{}' for volume '{}'",
+                        session.getSessionKey(),
+                        session.getMasterVolumeName());
+                if (Guid.isNullOrEmpty(session.getId())) {
+                    session.setId(Guid.newGuid());
+                }
+                getGeoRepDao().save(session);
+                
logGeoRepMessage(AuditLogType.GLUSTER_GEOREP_SESSION_DETECTED_FROM_CLI, 
cluster.getId(), session);
+            } else {
+                session.setId(sessionInDb.getId());
+                getGeoRepDao().updateSession(session);
+            }
+            //update the session details object with session id.
+            for (GlusterGeoRepSessionDetails sessDetails : 
session.getSessionDetails()) {
+                sessDetails.setSessionId(session.getId());
+            }
+            
getGeoRepDao().saveOrUpdateDetailsInBatch(session.getSessionDetails());
+        }
+
+    }
+
+    private void removeDeletedSessions(Guid clusterId, final Map<String, 
GlusterGeoRepSession> sessionsMap) {
+        List<GlusterGeoRepSession> sessionsInDb = 
getGeoRepDao().getGeoRepSessionsInCluster(clusterId);
+        if (sessionsInDb == null || sessionsInDb.isEmpty()) {
+            return;
+        }
+        List<GlusterGeoRepSession> sessionsToDelete = new ArrayList<>();
+        for (GlusterGeoRepSession grepSession: sessionsInDb) {
+            if (sessionsMap.get(grepSession.getSessionKey()) == null) {
+                sessionsToDelete.add(grepSession);
+            }
+        }
+
+        for (final GlusterGeoRepSession session : sessionsToDelete) {
+            log.debug("geo-rep session '{}' detected removed for volume '{}'",
+                    session.getSessionKey(),
+                    session.getMasterVolumeName());
+            getGeoRepDao().remove(session.getId());
+            
logGeoRepMessage(AuditLogType.GLUSTER_GEOREP_SESSION_DELETED_FROM_CLI, 
clusterId, session);
+        }
+    }
+
+    private void logGeoRepMessage(AuditLogType logType, Guid clusterId, final 
GlusterGeoRepSession session) {
+        logUtil.logAuditMessage(clusterId, null, null,
+                logType,
+                new HashMap<String, String>() {
+                    {
+                        put(GlusterConstants.VOLUME_NAME, 
session.getMasterVolumeName());
+                        put("geoRepSessionKey", session.getSessionKey());
+                    }
+                });
+    }
+
+    /**
+     * This method updates the status depending on health of individual nodes
+     *
+     * @param volume
+     * @param session
+     */
+    private void updateGeoRepStatus(GlusterVolumeEntity volume, 
GlusterGeoRepSession session) {
+
+        List<HashSet<GeoRepSessionStatus>> list = new ArrayList<>();
+        // grouped node status
+        int replicaCount = volume.getReplicaCount() == 0 ? 1 : 
volume.getReplicaCount();
+        for (int i = 0; i < volume.getBricks().size(); i = i + replicaCount) {
+            HashSet<GeoRepSessionStatus> subVolumeStatusSet = new HashSet<>();
+            int j = 0;
+            while (j < replicaCount) {
+                Guid brickId = volume.getBricks().get(i + j).getId();
+                subVolumeStatusSet.add(getStatusForBrickFromSession(session, 
brickId));
+                j++;
+            }
+            list.add(subVolumeStatusSet);
+        }
+
+        session.setStatus(GeoRepSessionStatus.ACTIVE);
+        // iterate through grouped status to set consolidated status
+        for (HashSet<GeoRepSessionStatus> subVolumeStatusValues : list) {
+            if (subVolumeStatusValues.contains(GeoRepSessionStatus.ACTIVE)) {
+                // healthy
+                continue;
+            } else if 
(subVolumeStatusValues.contains(GeoRepSessionStatus.FAULTY)) {
+                session.setStatus(GeoRepSessionStatus.FAULTY);
+                // if any one of the sub-volume is faulty, the overall session 
status if faulty
+                return;
+            }
+            // override status in case of these values
+            if (ArrayUtils.contains(overridableStatuses, session.getStatus())) 
{
+                if (subVolumeStatusValues.size() == 1) {
+                    session.setStatus((GeoRepSessionStatus) 
subVolumeStatusValues.toArray()[0]);
+                } else {
+                    // if status values in sub-volume are not the same, what 
do we do?
+                    // this should not happen, so we'll log it for now
+                    log.info("Multiple status values found in volume '{}'", 
session.getMasterVolumeName());
+                }
+            }
+        }
+
+    }
+
+    private GeoRepSessionStatus 
getStatusForBrickFromSession(GlusterGeoRepSession session, Guid masterBrickId) {
+        if (session.getSessionDetails() == null) {
+            return null;
+        }
+        for (GlusterGeoRepSessionDetails sessionDetail : 
session.getSessionDetails()) {
+            if (sessionDetail.getMasterBrickId().equals(masterBrickId)) {
+                return sessionDetail.getStatus();
+            }
+        }
+        return GeoRepSessionStatus.UNKNOWN;
+    }
+
+    private Map<String, GlusterGeoRepSession> getSessionsForCluster(VDSGroup 
cluster) {
+        VDS upServer = getClusterUtils().getRandomUpServer(cluster.getId());
+        if (upServer == null) {
+            log.debug("No UP server found in cluster '{}' for geo-rep 
monitoring", cluster.getName());
+            return null;
+        }
+        // get details of geo-rep sessions in cluster
+        VDSReturnValue returnValue = 
runVdsCommand(VDSCommandType.GetGlusterVolumeGeoRepStatus,
+                new GlusterVolumeGeoRepSessionVDSParameters(upServer.getId(), 
null));
+        if (returnValue.getSucceeded()) {
+            List<GlusterGeoRepSession> sessions = (List<GlusterGeoRepSession>) 
returnValue.getReturnValue();
+            HashMap<String, GlusterGeoRepSession> sessionsMap = new 
HashMap<>();
+            if (sessions == null) {
+                return sessionsMap;
+            }
+            for (GlusterGeoRepSession session : sessions) {
+                sessionsMap.put(session.getSessionKey(), session);
+            }
+            return sessionsMap;
+        } else {
+            log.error("VDS error {}", returnValue.getVdsError().getMessage());
+            log.debug("VDS error", returnValue.getVdsError());
+            return null;
+        }
+
+    }
+
+    private GlusterVolumeEntity getVolume(VDSGroup cluster, String 
masterVolumeName) {
+        return getVolumeDao().getByName(cluster.getId(), masterVolumeName);
+    }
+
+    private boolean supportsGlusterGeoRepFeature(VDSGroup cluster) {
+        return cluster.supportsGlusterService()
+                && 
GlusterFeatureSupported.glusterGeoReplication(cluster.getcompatibility_version());
+    }
+
+}
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 56242e2..57beb7b 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
@@ -26,6 +26,7 @@
 import org.ovirt.engine.core.dao.VdsStatisticsDAO;
 import org.ovirt.engine.core.dao.gluster.GlusterBrickDao;
 import org.ovirt.engine.core.dao.gluster.GlusterClusterServiceDao;
+import org.ovirt.engine.core.dao.gluster.GlusterGeoRepDao;
 import org.ovirt.engine.core.dao.gluster.GlusterHooksDao;
 import org.ovirt.engine.core.dao.gluster.GlusterOptionDao;
 import org.ovirt.engine.core.dao.gluster.GlusterServerDao;
@@ -129,6 +130,10 @@
         return DbFacade.getInstance().getStepDao();
     }
 
+    protected GlusterGeoRepDao getGeoRepDao() {
+        return DbFacade.getInstance().getGlusterGeoRepDao();
+    }
+
     /**
      * 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 c0f6a27..96e19aa 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
@@ -64,6 +64,14 @@
                 getRefreshRate(ConfigValues.GlusterRefreshRateTasks),
                 TimeUnit.SECONDS);
 
+        scheduler.scheduleAFixedDelayJob(GlusterGeoRepSyncJob.getInstance(),
+                "gluster_georep_poll_event",
+                new Class[0] ,
+                new Class [0],
+                getRefreshRate(ConfigValues.GlusterRefreshRateGeoRepDiscovery),
+                getRefreshRate(ConfigValues.GlusterRefreshRateGeoRepDiscovery),
+                TimeUnit.SECONDS);
+
     }
 
     private static boolean glusterModeSupported() {
diff --git 
a/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/gluster/GlusterGeoRepSyncJobTest.java
 
b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/gluster/GlusterGeoRepSyncJobTest.java
new file mode 100644
index 0000000..3f4de6d
--- /dev/null
+++ 
b/backend/manager/modules/bll/src/test/java/org/ovirt/engine/core/bll/gluster/GlusterGeoRepSyncJobTest.java
@@ -0,0 +1,185 @@
+package org.ovirt.engine.core.bll.gluster;
+
+import static org.mockito.Matchers.any;
+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.List;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+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.GeoRepSessionStatus;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterBrickEntity;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterGeoRepSession;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterGeoRepSessionDetails;
+import org.ovirt.engine.core.common.businessentities.gluster.GlusterStatus;
+import 
org.ovirt.engine.core.common.businessentities.gluster.GlusterVolumeEntity;
+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.gluster.GlusterVolumeGeoRepSessionVDSParameters;
+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.VdsGroupDAO;
+import org.ovirt.engine.core.dao.gluster.GlusterGeoRepDao;
+import org.ovirt.engine.core.dao.gluster.GlusterVolumeDao;
+import org.ovirt.engine.core.utils.MockConfigRule;
+
+@RunWith(MockitoJUnitRunner.class)
+public class GlusterGeoRepSyncJobTest {
+
+    @Mock
+    private GlusterGeoRepDao geoRepDao;
+
+    @Mock
+    private ClusterUtils clusterUtils;
+
+    @Mock
+    private VdsGroupDAO clusterDao;
+
+    @Mock
+    private GlusterVolumeDao volumeDao;
+
+    private GlusterGeoRepSyncJob syncJob;
+
+    @Mock
+    private GlusterAuditLogUtil logUtil;
+
+    @ClassRule
+    public static MockConfigRule mcr = new MockConfigRule(
+            mockConfig(ConfigValues.GlusterGeoReplicationEnabled, 
Version.v3_5.toString(), true),
+            mockConfig(ConfigValues.GlusterGeoReplicationEnabled, 
Version.v3_4.toString(), false)
+            );
+
+    @Before
+    public void init() {
+        syncJob = Mockito.spy(GlusterGeoRepSyncJob.getInstance());
+        MockitoAnnotations.initMocks(this);
+        doReturn(clusterDao).when(syncJob).getClusterDao();
+        doReturn(geoRepDao).when(syncJob).getGeoRepDao();
+        doReturn(volumeDao).when(syncJob).getVolumeDao();
+        doReturn(clusterUtils).when(syncJob).getClusterUtils();
+        syncJob.setLogUtil(logUtil);
+        doReturn(getClusters()).when(clusterDao).getAll();
+        doReturn(getVolume()).when(volumeDao).getByName(any(Guid.class), 
any(String.class));
+        
doReturn(getServer()).when(clusterUtils).getRandomUpServer(any(Guid.class));
+    }
+
+    @Test
+    public void testSync() {
+
+        doReturn(getSessionsVDSReturnVal(true, 2)).when(syncJob)
+                .runVdsCommand(eq(VDSCommandType.GetGlusterVolumeGeoRepStatus),
+                        any(GlusterVolumeGeoRepSessionVDSParameters.class));
+        syncJob.refreshGeoRepData();
+        Mockito.verify(geoRepDao, 
times(2)).save(any(GlusterGeoRepSession.class));
+    }
+
+    @Test
+    public void testSyncWhenNoSessions() {
+
+        doReturn(getSessionsVDSReturnVal(true, 0)).when(syncJob)
+                .runVdsCommand(eq(VDSCommandType.GetGlusterVolumeGeoRepStatus),
+                        any(GlusterVolumeGeoRepSessionVDSParameters.class));
+        syncJob.refreshGeoRepData();
+        Mockito.verify(geoRepDao, 
times(0)).save(any(GlusterGeoRepSession.class));
+    }
+
+    private Object getSessionsVDSReturnVal(boolean ret, int count) {
+        VDSReturnValue vdsRetValue = new VDSReturnValue();
+        vdsRetValue.setSucceeded(ret);
+        if (ret) {
+            vdsRetValue.setReturnValue(getSessions(count));
+        } else {
+            vdsRetValue.setReturnValue(null);
+        }
+        return vdsRetValue;
+    }
+
+    private List<GlusterGeoRepSession> getSessions(int count) {
+        List<GlusterGeoRepSession> sessions = new 
ArrayList<GlusterGeoRepSession>();
+        for (int i = 0; i < count; i++) {
+            sessions.add(getSession());
+        }
+        return sessions;
+    }
+
+    private GlusterGeoRepSession getSession() {
+        GlusterGeoRepSession session = new GlusterGeoRepSession();
+        session.setMasterVolumeName("VOL1");
+        session.setId(Guid.newGuid());
+        session.setSessionKey(session.getId() + session.getMasterVolumeName());
+        session.setStatus(GeoRepSessionStatus.ACTIVE);
+        session.setSessionDetails(getSessionDetailsList());
+        return session;
+    }
+
+    private ArrayList<GlusterGeoRepSessionDetails> getSessionDetailsList() {
+        ArrayList<GlusterGeoRepSessionDetails> list = new ArrayList<>();
+        GlusterGeoRepSessionDetails details = new 
GlusterGeoRepSessionDetails();
+        details.setMasterBrickId(Guid.newGuid());
+        list.add(details);
+        return list;
+    }
+
+    private List<VDSGroup> getClusters() {
+        List<VDSGroup> list = new ArrayList<>();
+        list.add(createCluster(Version.v3_4));
+        list.add(createCluster(Version.v3_5));
+        return list;
+    }
+
+    private VDSGroup createCluster(Version v) {
+        VDSGroup cluster = new VDSGroup();
+        cluster.setId(Guid.newGuid());
+        cluster.setName("cluster");
+        cluster.setGlusterService(true);
+        cluster.setVirtService(false);
+        cluster.setcompatibility_version(v);
+        return cluster;
+    }
+
+    private VDS getServer() {
+        VDS vds = new VDS();
+        vds.setId(Guid.newGuid());
+        return vds;
+    }
+
+    private GlusterVolumeEntity getVolume() {
+        GlusterVolumeEntity volume = new GlusterVolumeEntity();
+        volume.setName("VOL1");
+        volume.setClusterId(Guid.newGuid());
+        volume.setId(Guid.newGuid());
+        volume.setReplicaCount(2);
+
+        GlusterBrickEntity brick = new GlusterBrickEntity();
+        brick.setVolumeId(volume.getId());
+        brick.setBrickDirectory("/export/testvol1");
+        brick.setStatus(GlusterStatus.UP);
+        brick.setBrickOrder(0);
+        volume.addBrick(brick);
+
+        GlusterBrickEntity brick2 = new GlusterBrickEntity();
+        brick2.setVolumeId(volume.getId());
+        brick2.setBrickDirectory("/export/testvol1");
+        brick2.setStatus(GlusterStatus.UP);
+        brick2.setBrickOrder(1);
+        volume.addBrick(brick2);
+
+        return volume;
+    }
+
+}
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 a2254a1..6043d94 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
@@ -382,6 +382,8 @@
     GLUSTER_VOLUME_DETAILS_REFRESH(4093),
     GLUSTER_VOLUME_DETAILS_REFRESH_FAILED(4094, AuditLogSeverity.ERROR),
     USER_FORCE_SELECTED_SPM_STOP_FAILED(4096, AuditLogSeverity.ERROR),
+    GLUSTER_GEOREP_SESSION_DELETED_FROM_CLI(4097, AuditLogSeverity.WARNING),
+    GLUSTER_GEOREP_SESSION_DETECTED_FROM_CLI(4098, AuditLogSeverity.WARNING),
     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/config/ConfigValues.java
 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/config/ConfigValues.java
index 0b73082..4c97df3 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
@@ -1457,6 +1457,14 @@
     @DefaultValueAttribute("300")
     GlusterRefreshRateSnapshotDiscovery,
 
+    @TypeConverterAttribute(Boolean.class)
+    @DefaultValueAttribute("true")
+    GlusterGeoReplicationEnabled,
+
+    @TypeConverterAttribute(Integer.class)
+    @DefaultValueAttribute("3600")
+    GlusterRefreshRateGeoRepDiscovery,
+
     @TypeConverterAttribute(String.class)
     @DefaultValueAttribute("AttestationService/resources/PollHosts")
     PollUri,
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 564f731..2b2a529 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
@@ -80,4 +80,15 @@
             return false;
         }
     }
+
+    /**
+    *
+    * @param version
+    *            Compatibility version to check for.
+    * @return <code>true</code> if gluster geo-replication management feature 
is enabled,
+    *         <code>false</code> if it's not.
+    */
+   public static boolean glusterGeoReplication(Version version) {
+       return supportedInConfig(ConfigValues.GlusterGeoReplicationEnabled, 
version);
+   }
 }
diff --git 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDao.java
 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDao.java
index 1e8f470..d1664f0 100644
--- 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDao.java
+++ 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDao.java
@@ -17,6 +17,8 @@
 
     public void saveDetails(GlusterGeoRepSessionDetails geoRepSessionDetails);
 
+    public void saveDetailsInBatch(List<GlusterGeoRepSessionDetails> 
geoRepSessionDetailsList);
+
     public void saveConfig(GlusterGeoRepSessionConfiguration 
geoRepSessionConfig);
 
     /**
@@ -30,16 +32,24 @@
 
     public List<GlusterGeoRepSession> getGeoRepSessions(Guid masterVolumeId);
 
+    public List<GlusterGeoRepSession> getGeoRepSessionsInCluster(Guid 
clusterId);
+
     public void remove(Guid id);
 
     public void updateSession(GlusterGeoRepSession geoRepSession);
 
     public void updateDetails(GlusterGeoRepSessionDetails 
geoRepSessionDetails);
 
+    public void updateDetailsInBatch(List<GlusterGeoRepSessionDetails> 
geoRepSessionDetailsObjs);
+
+    public void saveOrUpdateDetailsInBatch(List<GlusterGeoRepSessionDetails> 
geoRepSessionDetailsObjs);
+
     public void updateConfig(GlusterGeoRepSessionConfiguration 
geoRepSessionConfig);
 
     public List<GlusterGeoRepSessionDetails> getGeoRepSessionDetails(Guid 
sessionId);
 
+    public GlusterGeoRepSessionDetails getGeoRepSessionDetails(Guid sessionId, 
Guid masterBrickId);
+
     public List<GlusterGeoRepSessionConfiguration> getGeoRepSessionConfig(Guid 
sessionId);
 
  }
diff --git 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDaoDbFacadeImpl.java
 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDaoDbFacadeImpl.java
index 6bb6771..864c1b5 100644
--- 
a/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDaoDbFacadeImpl.java
+++ 
b/backend/manager/modules/dal/src/main/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDaoDbFacadeImpl.java
@@ -2,6 +2,7 @@
 
 import java.sql.ResultSet;
 import java.sql.SQLException;
+import java.util.ArrayList;
 import java.util.List;
 
 import org.ovirt.engine.core.common.businessentities.gluster.GeoRepCrawlStatus;
@@ -119,9 +120,21 @@
     }
 
     @Override
+    public List<GlusterGeoRepSession> getGeoRepSessionsInCluster(Guid 
clusterId) {
+        return 
getCallsHandler().executeReadList("GetGlusterGeoRepSessionsByClusterId", 
georepSessionRowMapper,
+                getCustomMapSqlParameterSource().addValue("cluster_id", 
clusterId));
+    }
+
+    @Override
     public List<GlusterGeoRepSessionDetails> getGeoRepSessionDetails(Guid 
sessionId) {
         return 
getCallsHandler().executeReadList("GetGlusterGeoRepSessionDetails", 
georepSessionDetailsRowMapper,
                 createIdParameterMapper(sessionId));
+    }
+
+    @Override
+    public GlusterGeoRepSessionDetails getGeoRepSessionDetails(Guid sessionId, 
Guid masterBrickId) {
+        return 
getCallsHandler().executeRead("GetGlusterGeoRepSessionDetailsForBrick", 
georepSessionDetailsRowMapper,
+                createIdParameterMapper(sessionId).addValue("master_brick_id", 
masterBrickId));
     }
 
     @Override
@@ -178,7 +191,7 @@
     public void updateSession(GlusterGeoRepSession geoRepSession) {
         
getCallsHandler().executeModification("UpdateGlusterGeoRepSessionStatus",
                 createIdParameterMapper(geoRepSession.getId())
-                .addValue("status", geoRepSession.getStatus()));
+                .addValue("status", 
EnumUtils.nameOrNull(geoRepSession.getStatus())));
     }
 
     @Override
@@ -196,6 +209,42 @@
     }
 
     @Override
+    public void saveOrUpdateDetailsInBatch(List<GlusterGeoRepSessionDetails> 
geoRepSessionDetailsObjs) {
+        List<GlusterGeoRepSessionDetails> insertList = new ArrayList<>();
+        List<GlusterGeoRepSessionDetails> updateList = new ArrayList<>();
+        for (GlusterGeoRepSessionDetails details : geoRepSessionDetailsObjs) {
+            if (getGeoRepSessionDetails(details.getSessionId(), 
details.getMasterBrickId()) == null) {
+                insertList.add(details);
+            } else {
+                updateList.add(details);
+            }
+        }
+        saveDetailsInBatch(insertList);
+        updateDetailsInBatch(updateList);
+    }
+
+    @Override
+    public void saveDetailsInBatch(List<GlusterGeoRepSessionDetails> 
geoRepSessionDetailsList) {
+        
getCallsHandler().executeStoredProcAsBatch("InsertGlusterGeoRepSessionDetail",
+                geoRepSessionDetailsList, getDetailsBatchMapper());
+    }
+
+    @Override
+    public void updateDetailsInBatch(List<GlusterGeoRepSessionDetails> 
geoRepSessionDetailsObjs) {
+        
getCallsHandler().executeStoredProcAsBatch("UpdateGlusterGeoRepSessionDetail",
+                geoRepSessionDetailsObjs, getDetailsBatchMapper());
+    }
+
+    public MapSqlParameterMapper<GlusterGeoRepSessionDetails> 
getDetailsBatchMapper() {
+        return new MapSqlParameterMapper<GlusterGeoRepSessionDetails>() {
+            @Override
+            public MapSqlParameterSource map(GlusterGeoRepSessionDetails 
entity) {
+                return createFullParametersMapper(entity);
+            }
+        };
+    }
+
+    @Override
     public MapSqlParameterMapper<GlusterGeoRepSession> getBatchMapper() {
         return new MapSqlParameterMapper<GlusterGeoRepSession>() {
             @Override
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 1304f5a..d506a6d 100644
--- 
a/backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties
+++ 
b/backend/manager/modules/dal/src/main/resources/bundles/AuditLogMessages.properties
@@ -804,6 +804,8 @@
 GLUSTER_SERVICE_RESTART_FAILED=Could not re-start ${servicetype} service on 
host ${VdsName} on cluster ${VdsGroupName}.
 GLUSTER_VOLUME_BRICK_ADDED=Brick [${brickpath}] on host [${servername}] added 
to volume [${glusterVolumeName}]
 GLUSTER_BRICK_STATUS_CHANGED=Detected change in status of brick ${brickpath} 
of volume ${glusterVolumeName} from ${oldValue} to ${newValue}.
+GLUSTER_GEOREP_SESSION_DELETED_FROM_CLI=Detected deletion of geo-replication 
session ${geoRepSessionKey} from volume ${glusterVolumeName}
+GLUSTER_GEOREP_SESSION_DETECTED_FROM_CLI=Detected new geo-replication session 
${geoRepSessionKey} for volume ${glusterVolumeName}. Adding it to engine.
 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/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDaoTest.java
 
b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDaoTest.java
index b93c72e..dab2f92 100644
--- 
a/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDaoTest.java
+++ 
b/backend/manager/modules/dal/src/test/java/org/ovirt/engine/core/dao/gluster/GlusterGeoRepDaoTest.java
@@ -136,4 +136,9 @@
         assertEquals("NEW_VAL", fetchedSessionConfig.get(0).getValue());
     }
 
+    public void testGetAllInCluster() {
+        List<GlusterGeoRepSession> fetchedSessions = 
dao.getGeoRepSessionsInCluster(FixturesTool.GLUSTER_CLUSTER_ID);
+        assertEquals(1, fetchedSessions.size());
+    }
+
 }
diff --git 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/gluster/GlusterVolumeGeoRepStatusForXmlRpc.java
 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/gluster/GlusterVolumeGeoRepStatusForXmlRpc.java
index 30d0e5f..5bc5a70 100644
--- 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/gluster/GlusterVolumeGeoRepStatusForXmlRpc.java
+++ 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/gluster/GlusterVolumeGeoRepStatusForXmlRpc.java
@@ -35,7 +35,6 @@
 
     protected GlusterGeoRepSessionDetails getSessionDetails(Map<String, 
Object> innerMap, GlusterGeoRepSession session) {
         GlusterGeoRepSessionDetails details = new 
GlusterGeoRepSessionDetails();
-        details.setSessionId(session.getId());
         Guid masterNodeGlusterId;
         if (innerMap.containsKey(MASTER_NODE_UUID)) {
             masterNodeGlusterId = new 
Guid(innerMap.get(MASTER_NODE_UUID).toString());
@@ -71,14 +70,12 @@
 
     protected GlusterGeoRepSession getSession(String masterVolumeName, 
Map<String, Object> innerMap) {
         GlusterGeoRepSession geoRepSession = new GlusterGeoRepSession();
-        // sessionslave in the form -
+        // sessionslave in the form - the uuid is the gluster server uuid on 
master
         // 
<session_slave>11ae7a03-e793-4270-8fc4-b42def8b3051:ssh://192.168.122.14::slave2</session_slave>
         String sessionKey = (String) innerMap.get(SESSION_SLAVE);
         String sessSplit[] = sessionKey.split("([://]+)");
-        String sessionId = sessSplit[0];
         String slaveNode = sessSplit[sessSplit.length - 2];
         String slaveVolume = sessSplit[sessSplit.length - 1];
-        geoRepSession.setId(Guid.createGuidFromString(sessionId));
         geoRepSession.setSlaveHostName(slaveNode);
         geoRepSession.setSlaveVolumeName(slaveVolume);
         geoRepSession.setSessionKey(sessionKey);
diff --git a/packaging/dbscripts/gluster_georep_sp.sql 
b/packaging/dbscripts/gluster_georep_sp.sql
index b365231..61ae9dd 100644
--- a/packaging/dbscripts/gluster_georep_sp.sql
+++ b/packaging/dbscripts/gluster_georep_sp.sql
@@ -84,7 +84,8 @@
     files_pending = v_files_pending,
     bytes_pending = v_bytes_pending,
     deletes_pending = v_deletes_pending,
-    files_skipped = v_files_skipped
+    files_skipped = v_files_skipped,
+    _update_date = LOCALTIMESTAMP
     WHERE session_id = v_session_id AND master_brick_id = v_master_brick_id;
 END; $procedure$
 LANGUAGE plpgsql;
@@ -96,7 +97,8 @@
 AS $procedure$
 BEGIN
     UPDATE gluster_georep_config
-    SET config_value = v_config_value
+    SET config_value = v_config_value,
+    _update_date = LOCALTIMESTAMP
     WHERE session_id = v_session_id AND config_key = v_config_key;
 END; $procedure$
 LANGUAGE plpgsql;
@@ -127,6 +129,18 @@
 END; $procedure$
 LANGUAGE plpgsql;
 
+Create or replace FUNCTION GetGlusterGeoRepSessionsByClusterId(v_cluster_id 
UUID)
+RETURNS SETOF gluster_georep_session STABLE
+AS $procedure$
+BEGIN
+    RETURN QUERY SELECT session_id, master_volume_id, session_key, 
slave_host_uuid,
+    slave_host_name, slave_volume_id, slave_volume_name, georep.status,
+    georep._create_date, georep._update_date
+    FROM  gluster_georep_session georep JOIN gluster_volumes ON 
master_volume_id = id
+    WHERE cluster_id = v_cluster_id order by slave_volume_name asc;
+END; $procedure$
+LANGUAGE plpgsql;
+
 Create or replace FUNCTION GetGlusterGeoRepSessionByKey(v_session_key 
VARCHAR(150))
 RETURNS SETOF gluster_georep_session STABLE
 AS $procedure$
@@ -145,7 +159,8 @@
 AS $procedure$
 BEGIN
     UPDATE gluster_georep_session
-    SET status = v_status
+    SET status = v_status,
+    _update_date = LOCALTIMESTAMP
     WHERE session_id = v_session_id;
 END; $procedure$
 LANGUAGE plpgsql;
@@ -162,6 +177,20 @@
 END; $procedure$
 LANGUAGE plpgsql;
 
+Create or replace FUNCTION GetGlusterGeoRepSessionDetailsForBrick(v_session_id 
UUID,
+                                                                  
v_master_brick_id UUID)
+RETURNS SETOF gluster_georep_session_details STABLE
+AS $procedure$
+BEGIN
+    RETURN QUERY SELECT session_id, master_brick_id, slave_host_uuid,
+    slave_host_name, status, checkpoint_status, crawl_status, files_synced, 
files_pending,
+    bytes_pending, deletes_pending, files_skipped, _update_date
+    FROM  gluster_georep_session_details
+    WHERE session_id = v_session_id AND master_brick_id = v_master_brick_id;
+END; $procedure$
+LANGUAGE plpgsql;
+
+
 Create or replace FUNCTION GetGlusterGeoRepSessionConfig(v_session_id UUID)
 RETURNS SETOF gluster_georep_config STABLE
 AS $procedure$
diff --git 
a/packaging/dbscripts/upgrade/03_05_1270_add_idx_gluster_georep_slavevolname.sql
 
b/packaging/dbscripts/upgrade/03_05_1270_add_idx_gluster_georep_slavevolname.sql
new file mode 100644
index 0000000..6795496
--- /dev/null
+++ 
b/packaging/dbscripts/upgrade/03_05_1270_add_idx_gluster_georep_slavevolname.sql
@@ -0,0 +1,2 @@
+DROP INDEX if exists IDX_georep_slave_volume_name;
+CREATE INDEX IDX_georep_slave_volume_name ON 
gluster_georep_session(slave_volume_name);
diff --git a/packaging/dbscripts/upgrade/pre_upgrade/0000_config.sql 
b/packaging/dbscripts/upgrade/pre_upgrade/0000_config.sql
index 8ffdc89..3150905 100644
--- a/packaging/dbscripts/upgrade/pre_upgrade/0000_config.sql
+++ b/packaging/dbscripts/upgrade/pre_upgrade/0000_config.sql
@@ -191,6 +191,15 @@
 select fn_db_add_config_value('GlusterVolumeSnapshotSupported', 'false', 
'3.4');
 select fn_db_add_config_value('GlusterVolumeSnapshotSupported', 'false', 
'3.5');
 select fn_db_add_config_value('GlusterRefreshRateSnapshotDiscovery', '300', 
'general');
+-- Gluster Geo-replication --
+select fn_db_add_config_value('GlusterGeoReplicationEnabled', 'false', '3.0');
+select fn_db_add_config_value('GlusterGeoReplicationEnabled', 'false', '3.1');
+select fn_db_add_config_value('GlusterGeoReplicationEnabled', 'false', '3.2');
+select fn_db_add_config_value('GlusterGeoReplicationEnabled', 'false', '3.3');
+select fn_db_add_config_value('GlusterGeoReplicationEnabled', 'false', '3.4');
+select fn_db_add_config_value('GlusterGeoReplicationEnabled', 'false', '3.5');
+select fn_db_add_config_value('GlusterRefreshRateGeoRepStatus', '300', 
'general');
+select fn_db_add_config_value('GlusterRefreshRateGeoRepDiscovery', '3600', 
'general');
 
 -- OpenStack related
 select fn_db_add_config_value('KeystoneAuthUrl', '', 'general');


-- 
To view, visit https://gerrit.ovirt.org/39574
To unsubscribe, visit https://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I3304addda17cf49eee93f311e043b0e15212cd91
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: ovirt-engine-3.5-gluster
Gerrit-Owner: Sahina Bose <[email protected]>
_______________________________________________
Engine-patches mailing list
[email protected]
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to