Yair Zaslavsky has uploaded a new change for review.

Change subject: aaa: Stop using proxies
......................................................................

aaa: Stop using proxies

This patch will remove usage of DirectoryProxy and AuthenticatorProxy in a 
gradual manner.

1. Adding getters to ExtensionProxy to both proxies, so we can start working 
with the extensions API
at bll commands

2. Changing LoginBaseCommand and AuthenticationFilter to work directly with the 
new API
3. Reducing to mininum the code in AuthenticatorProxy - this proxy is still 
used as a bridge between
authz and profile.

Change-Id: I916012eab61a96bdb0f366d9dc8462325d7f726f
Topic: AAA
Signed-off-by: Yair Zaslavsky <yzasl...@redhat.com>
---
M 
backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/AuthenticationFilter.java
M 
backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/AuthenticatorProxy.java
M 
backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/DirectoryProxy.java
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/LoginBaseCommand.java
4 files changed, 147 insertions(+), 131 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/02/26602/1

diff --git 
a/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/AuthenticationFilter.java
 
b/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/AuthenticationFilter.java
index 356ffc8..a5327b6 100644
--- 
a/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/AuthenticationFilter.java
+++ 
b/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/AuthenticationFilter.java
@@ -16,6 +16,8 @@
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
+import org.ovirt.engine.api.extensions.aaa.Authn;
+
 /**
  * This filter should be added to the {@code web.xml} file to the applications 
that want to use the authentication
  * mechanism implemented in this package.
@@ -62,8 +64,10 @@
                     profiles = new ArrayList<AuthenticationProfile>(1);
                     for (AuthenticationProfile profile : 
AuthenticationProfileRepository.getInstance().getProfiles()) {
                         if (profile != null) {
-                            Authenticator authenticator = 
profile.getAuthenticator();
-                            if (authenticator.isNegotiationAuth()) {
+                            if ((((AuthenticatorProxy) 
profile.getAuthenticator()).getExtension()
+                                    .getContext()
+                                    .<Long> get(Authn.ContextKeys.CAPABILITIES)
+                                    .longValue() & 
Authn.Capabilities.AUTHENTICATE_NEGOTIATE) == 
Authn.Capabilities.AUTHENTICATE_NEGOTIATE) {
                                 profiles.add(0, profile);
                             }
 
diff --git 
a/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/AuthenticatorProxy.java
 
b/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/AuthenticatorProxy.java
index 6db7af4..a2f7ccd 100644
--- 
a/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/AuthenticatorProxy.java
+++ 
b/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/AuthenticatorProxy.java
@@ -3,9 +3,6 @@
 import java.util.Properties;
 
 import org.ovirt.engine.api.extensions.Base;
-import org.ovirt.engine.api.extensions.ExtMap;
-import org.ovirt.engine.api.extensions.aaa.Authn;
-import org.ovirt.engine.api.extensionsold.AAAExtensionException;
 import org.ovirt.engine.core.extensions.mgr.ExtensionProxy;
 
 public class AuthenticatorProxy extends Authenticator {
@@ -16,28 +13,9 @@
         this.extension = extension;
     }
 
-    @Override
     @Deprecated
+    @Override
     public void init() {
-    }
-
-    @Override
-    @Deprecated
-    public void authenticate(String user, String password) {
-        ExtMap outputMap = extension.invoke(new ExtMap().mput(
-                    Base.InvokeKeys.COMMAND,
-                    Authn.InvokeCommands.AUTHENTICATE_CREDENTIALS
-                ).mput(
-                    Authn.InvokeKeys.USER,
-                    user
-                ).mput(
-                   Authn.InvokeKeys.CREDENTIALS,
-                   password
-                )
-        );
-        if (outputMap.<Integer> get(Authn.InvokeKeys.RESULT) == 
Authn.AuthResult.CREDENTIALS_INVALID) {
-            throw new 
AAAExtensionException(AAAExtensionException.AAAExtensionError.INCORRECT_CREDENTIALS,
 "");
-        }
     }
 
     @Override
@@ -53,17 +31,10 @@
                 .getProperty("ovirt.engine.aaa.authn.profile.name");
     }
 
-    @Override
-    @Deprecated
-    public boolean isNegotiationAuth() {
-        return (extension.getContext().<Long> 
get(Authn.ContextKeys.CAPABILITIES).longValue() & 
Authn.Capabilities.AUTHENTICATE_NEGOTIATE) == 
Authn.Capabilities.AUTHENTICATE_NEGOTIATE;
+    public ExtensionProxy getExtension() {
+        return extension;
     }
 
-    @Override
-    @Deprecated
-    public boolean isPasswordAuth() {
-        return (extension.getContext().<Long> 
get(Authn.ContextKeys.CAPABILITIES).longValue() & 
Authn.Capabilities.AUTHENTICATE_PASSWORD) == 
Authn.Capabilities.AUTHENTICATE_PASSWORD;
-    }
 
 }
 
diff --git 
a/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/DirectoryProxy.java
 
b/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/DirectoryProxy.java
index 4efc2e9..66c116f 100644
--- 
a/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/DirectoryProxy.java
+++ 
b/backend/manager/modules/aaa/src/main/java/org/ovirt/engine/core/aaa/DirectoryProxy.java
@@ -123,6 +123,10 @@
         return extension.getContext().<String> 
get(Base.ContextKeys.INSTANCE_NAME);
     }
 
+    public ExtensionProxy getExtension() {
+        return extension;
+    }
+
     private List<DirectoryUser> populateUsers(final ExtUUID command, final 
ExtMap extMap) {
         final List<DirectoryUser> directoryUsers = new ArrayList<>();
         queryImpl(new QueryResultHandler() {
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/LoginBaseCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/LoginBaseCommand.java
index 136290a..8e75bcb 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/LoginBaseCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/LoginBaseCommand.java
@@ -1,15 +1,17 @@
 package org.ovirt.engine.core.bll;
 
 import java.util.Collections;
-import java.util.EnumMap;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.commons.lang.StringUtils;
-import org.ovirt.engine.api.extensionsold.AAAExtensionException;
-import 
org.ovirt.engine.api.extensionsold.AAAExtensionException.AAAExtensionError;
+import org.ovirt.engine.api.extensions.Base;
+import org.ovirt.engine.api.extensions.ExtMap;
+import org.ovirt.engine.api.extensions.aaa.Authn;
 import org.ovirt.engine.core.aaa.AuthenticationProfile;
 import org.ovirt.engine.core.aaa.AuthenticationProfileRepository;
-import org.ovirt.engine.core.aaa.Authenticator;
+import org.ovirt.engine.core.aaa.AuthenticatorProxy;
 import org.ovirt.engine.core.aaa.Directory;
 import org.ovirt.engine.core.aaa.DirectoryUser;
 import org.ovirt.engine.core.aaa.DirectoryUtils;
@@ -25,6 +27,7 @@
 import org.ovirt.engine.core.compat.Guid;
 import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogDirector;
 import org.ovirt.engine.core.dal.dbbroker.auditloghandling.AuditLogableBase;
+import org.ovirt.engine.core.extensions.mgr.ExtensionProxy;
 import org.ovirt.engine.core.utils.log.Log;
 import org.ovirt.engine.core.utils.log.LogFactory;
 import org.ovirt.engine.core.utils.threadpool.ThreadPoolUtil;
@@ -32,26 +35,27 @@
 public abstract class LoginBaseCommand<T extends LoginUserParameters> extends 
CommandBase<T> {
     protected static final Log log = LogFactory.getLog(LoginBaseCommand.class);
 
-    private static final EnumMap<AAAExtensionError, AuditLogType> auditLogMap 
= new EnumMap<>(AAAExtensionError.class);
-    private static final EnumMap<AAAExtensionError, VdcBllMessages> 
vdcBllMessagesMap = new EnumMap<>(AAAExtensionError.class);
+    private static final Map<Integer, AuditLogType> auditLogMap = new 
HashMap<>();
+    private static final Map<Integer, VdcBllMessages> vdcBllMessagesMap = new 
HashMap<>();
 
     static {
-        auditLogMap.put(AAAExtensionError.CREDENTIALS_EXPIRED, 
AuditLogType.USER_ACCOUNT_PASSWORD_EXPIRED);
-        auditLogMap.put(AAAExtensionError.GENERAL_ERROR, 
AuditLogType.USER_VDC_LOGIN_FAILED);
-        auditLogMap.put(AAAExtensionError.INCORRECT_CREDENTIALS, 
AuditLogType.AUTH_FAILED_INVALID_CREDENTIALS);
-        auditLogMap.put(AAAExtensionError.LOCKED_OR_DISABLED_ACCOUNT, 
AuditLogType.USER_ACCOUNT_DISABLED_OR_LOCKED);
-        auditLogMap.put(AAAExtensionError.TIMED_OUT, 
AuditLogType.AUTH_FAILED_CONNECTION_TIMED_OUT);
-        auditLogMap.put(AAAExtensionError.SERVER_IS_NOT_AVAILABLE, 
AuditLogType.AUTH_FAILED_CONNECTION_ERROR);
+        auditLogMap.put(Authn.AuthResult.CREDENTIALS_EXPIRED, 
AuditLogType.USER_ACCOUNT_PASSWORD_EXPIRED);
+        auditLogMap.put(Authn.AuthResult.GENERAL_ERROR, 
AuditLogType.USER_VDC_LOGIN_FAILED);
+        auditLogMap.put(Authn.AuthResult.CREDENTIALS_INVALID, 
AuditLogType.AUTH_FAILED_INVALID_CREDENTIALS);
+        auditLogMap.put(Authn.AuthResult.ACCOUNT_LOCKED, 
AuditLogType.USER_ACCOUNT_DISABLED_OR_LOCKED);
+        auditLogMap.put(Authn.AuthResult.ACCOUNT_DISABLED, 
AuditLogType.USER_ACCOUNT_DISABLED_OR_LOCKED);
+        auditLogMap.put(Authn.AuthResult.TIMED_OUT, 
AuditLogType.USER_ACCOUNT_DISABLED_OR_LOCKED);
 
-        vdcBllMessagesMap.put(AAAExtensionError.GENERAL_ERROR, 
VdcBllMessages.USER_FAILED_TO_AUTHENTICATE);
-        vdcBllMessagesMap.put(AAAExtensionError.INCORRECT_CREDENTIALS,
+        vdcBllMessagesMap.put(Authn.AuthResult.GENERAL_ERROR, 
VdcBllMessages.USER_FAILED_TO_AUTHENTICATE);
+        vdcBllMessagesMap.put(Authn.AuthResult.CREDENTIALS_INVALID,
                 
VdcBllMessages.USER_FAILED_TO_AUTHENTICATE_WRONG_USERNAME_OR_PASSWORD);
-        vdcBllMessagesMap.put(AAAExtensionError.LOCKED_OR_DISABLED_ACCOUNT, 
VdcBllMessages.USER_ACCOUNT_DISABLED);
-        vdcBllMessagesMap.put(AAAExtensionError.SERVER_IS_NOT_AVAILABLE,
-                
VdcBllMessages.USER_FAILED_TO_AUTHENTICATE_SERVER_IS_NOT_AVAILABLE);
-        vdcBllMessagesMap.put(AAAExtensionError.TIMED_OUT, 
VdcBllMessages.USER_FAILED_TO_AUTHENTICATE_TIMED_OUT);
-        vdcBllMessagesMap.put(AAAExtensionError.CREDENTIALS_EXPIRED, 
VdcBllMessages.USER_PASSWORD_EXPIRED);
+        vdcBllMessagesMap.put(Authn.AuthResult.ACCOUNT_LOCKED, 
VdcBllMessages.USER_ACCOUNT_DISABLED);
+        vdcBllMessagesMap.put(Authn.AuthResult.ACCOUNT_DISABLED, 
VdcBllMessages.USER_ACCOUNT_DISABLED);
+        vdcBllMessagesMap.put(Authn.AuthResult.TIMED_OUT, 
VdcBllMessages.USER_FAILED_TO_AUTHENTICATE_TIMED_OUT);
+        vdcBllMessagesMap.put(Authn.AuthResult.CREDENTIALS_EXPIRED, 
VdcBllMessages.USER_PASSWORD_EXPIRED);
     }
+
+    private ExtensionProxy extension;
 
     public LoginBaseCommand(T parameters) {
         super(parameters);
@@ -151,8 +155,10 @@
         }
 
         // Check that the authenticator provided by the profile supports 
password authentication:
-        Authenticator authenticator = profile.getAuthenticator();
-        if (!(authenticator.isPasswordAuth())) {
+        AuthenticatorProxy authenticator = (AuthenticatorProxy) 
profile.getAuthenticator();
+        extension = authenticator.getExtension();
+
+        if (!isPasswordAuth()) {
             log.errorFormat(
                 "Can't login user \"{0}\" because the authentication profile 
\"{1}\" doesn't support password " +
                 "authentication.",
@@ -177,89 +183,63 @@
             password = curPassword;
         }
         // Perform the actual authentication:
-        try {
-            authenticator.authenticate(loginName, password);
-        } catch (AAAExtensionException ex) {
-            log.infoFormat(
-                    "Can't login user \"{0}\" with authentication profile 
\"{1}\" because the authentication failed.",
-                    loginName,
-                    profileName);
-            AuditLogType auditLogType = auditLogMap.get(ex.getError());
-            //if found matching audit log type, and it's not general login 
failure audit log (which will be logged anyway due to CommandBase.log)
-            if (auditLogType != null && auditLogType != 
AuditLogType.USER_VDC_LOGIN_FAILED) {
-                logEventForUser(loginName, auditLogType);
+        boolean authenticated = authenticate(loginName, password);
+        if (authenticated) {
+            Directory directory = profile.getDirectory();
+            DirectoryUser directoryUser = directory.findUser(loginName);
+            if (directoryUser == null) {
+                log.infoFormat(
+                        "Can't login user \"{0}\" with authentication profile 
\"{1}\" because the user doesn't exist in the "
+                                +
+                                "directory.",
+                        loginName,
+                        profileName
+                        );
+                
addCanDoActionMessage(VdcBllMessages.USER_MUST_EXIST_IN_DIRECTORY);
+                return false;
             }
 
-            VdcBllMessages canDoActionMsg = 
vdcBllMessagesMap.get(ex.getError());
 
-            getReturnValue().setSucceeded(false);
-            if (canDoActionMsg == VdcBllMessages.USER_PASSWORD_EXPIRED) {
-                boolean addedUserPasswordExpiredCDA = false;
-                if (authenticator.getChangeExpiredPasswordMsg() != null) {
-                    
addCanDoActionMessage(VdcBllMessages.USER_PASSWORD_EXPIRED_CHANGE_MSG_PROVIDED);
-                    
getReturnValue().getCanDoActionMessages().add(String.format("$MSG %1$s", 
authenticator.getChangeExpiredPasswordMsg()));
-                    addedUserPasswordExpiredCDA = true;
-                }
-                if (authenticator.getChangeExpiredPasswordURL() != null) {
-                    
addCanDoActionMessage(VdcBllMessages.USER_PASSWORD_EXPIRED_CHANGE_URL_PROVIDED);
-                    
getReturnValue().getCanDoActionMessages().add(String.format("$URL %1$s", 
authenticator.getChangeExpiredPasswordURL()));
-                    addedUserPasswordExpiredCDA = true;
-                }
-                if (!addedUserPasswordExpiredCDA) {
-                    
addCanDoActionMessage(VdcBllMessages.USER_PASSWORD_EXPIRED);
-                }
-            } else {
-                
getReturnValue().getCanDoActionMessages().add(canDoActionMsg.name());
+            // Check that the user exists in the database, if it doesn't exist 
then we need to add it now:
+            dbUser = getDbUserDAO().getByExternalId(directory.getName(), 
directoryUser.getId());
+            if (dbUser == null) {
+                dbUser = new DbUser(directoryUser);
+                String groupIds = 
DirectoryUtils.getGroupIdsFromUser(directoryUser);
+                dbUser.setGroupIds(groupIds);
+                dbUser.setId(Guid.newGuid());
+                getDbUserDAO().save(dbUser);
             }
-            return false;
+
+            // Check login permissions. We do it here and not via the
+            // getPermissionCheckSubjects mechanism, because we need the user 
to be logged in to
+            // the system in order to perform this check. The user is indeed 
logged in when running every command
+            // except the login command
+            if (!checkUserAndGroupsAuthorization(dbUser.getId(),
+                    dbUser.getGroupIds(),
+                    getActionType().getActionGroup(),
+                    MultiLevelAdministrationHandler.BOTTOM_OBJECT_ID,
+                    VdcObjectType.Bottom,
+                    true)) {
+                
addCanDoActionMessage(VdcBllMessages.USER_NOT_AUTHORIZED_TO_PERFORM_ACTION);
+                return false;
+            }
+
+            // Retrieve the MLA admin status of the user.
+            // This may be redundant in some use-cases, but looking forward to 
Single Sign On,
+            // we will want this info
+            boolean isAdmin = 
MultiLevelAdministrationHandler.isAdminUser(dbUser);
+            log.debugFormat("Checking if user {0} is an admin, result {1}", 
dbUser.getLoginName(), isAdmin);
+            dbUser.setAdmin(isAdmin);
+            setCurrentUser(dbUser);
+
+            // Add the user password to the session, as it will be needed later
+            // when trying to log on to virtual machines:
+            SessionDataContainer.getInstance().setPassword(password);
+            return true;
         }
+        return false;
 
         // Check that the user exists in the directory associated to the 
authentication profile:
-        Directory directory = profile.getDirectory();
-        DirectoryUser directoryUser = directory.findUser(loginName);
-        if (directoryUser == null) {
-            log.infoFormat(
-                "Can't login user \"{0}\" with authentication profile \"{1}\" 
because the user doesn't exist in the " +
-                "directory.",
-                loginName, profileName
-            );
-            addCanDoActionMessage(VdcBllMessages.USER_MUST_EXIST_IN_DIRECTORY);
-            return false;
-        }
-
-
-        // Check that the user exists in the database, if it doesn't exist 
then we need to add it now:
-        dbUser = getDbUserDAO().getByExternalId(directory.getName(), 
directoryUser.getId());
-        if (dbUser == null) {
-            dbUser = new DbUser(directoryUser);
-            String groupIds = 
DirectoryUtils.getGroupIdsFromUser(directoryUser);
-            dbUser.setGroupIds(groupIds);
-            dbUser.setId(Guid.newGuid());
-            getDbUserDAO().save(dbUser);
-        }
-
-        // Check login permissions. We do it here and not via the
-        // getPermissionCheckSubjects mechanism, because we need the user to 
be logged in to
-        // the system in order to perform this check. The user is indeed 
logged in when running every command
-        // except the login command
-        if (!checkUserAndGroupsAuthorization(dbUser.getId(), 
dbUser.getGroupIds(), getActionType().getActionGroup(), 
MultiLevelAdministrationHandler.BOTTOM_OBJECT_ID, VdcObjectType.Bottom, true)) {
-            
addCanDoActionMessage(VdcBllMessages.USER_NOT_AUTHORIZED_TO_PERFORM_ACTION);
-            return false;
-        }
-
-        // Retrieve the MLA admin status of the user.
-        // This may be redundant in some use-cases, but looking forward to 
Single Sign On,
-        // we will want this info
-        boolean isAdmin = MultiLevelAdministrationHandler.isAdminUser(dbUser);
-        log.debugFormat("Checking if user {0} is an admin, result {1}", 
dbUser.getLoginName(), isAdmin);
-        dbUser.setAdmin(isAdmin);
-        setCurrentUser(dbUser);
-
-        // Add the user password to the session, as it will be needed later
-        // when trying to log on to virtual machines:
-        SessionDataContainer.getInstance().setPassword(password);
-
-        return true;
     }
 
     private void logEventForUser(String userName, AuditLogType auditLogType) {
@@ -297,4 +277,61 @@
         logable.setUserName(getParameters().getLoginName());
         AuditLogDirector.log(logable, AuditLogType.USER_VDC_LOGIN_FAILED);
     }
+
+    private boolean isPasswordAuth() {
+        return (extension.getContext().<Long> 
get(Authn.ContextKeys.CAPABILITIES).longValue() & 
Authn.Capabilities.AUTHENTICATE_PASSWORD) == 
Authn.Capabilities.AUTHENTICATE_PASSWORD;
+    }
+
+    private boolean authenticate(String user, String password) {
+        boolean result = true;
+        ExtMap outputMap = extension.invoke(new ExtMap().mput(
+                Base.InvokeKeys.COMMAND,
+                Authn.InvokeCommands.AUTHENTICATE_CREDENTIALS
+                ).mput(
+                        Authn.InvokeKeys.USER,
+                        user
+                ).mput(
+                        Authn.InvokeKeys.CREDENTIALS,
+                        password
+                ));
+
+        int authResult = outputMap.<Integer>get(Authn.InvokeKeys.RESULT);
+        if (authResult != Authn.AuthResult.SUCCESS) {
+            log.infoFormat(
+                    "Can't login user \"{0}\" with authentication profile 
\"{1}\" because the authentication failed.",
+                    user,
+                    getParameters().getProfileName());
+
+            AuditLogType auditLogType = auditLogMap.get(authResult);
+            // if found matching audit log type, and it's not general login 
failure audit log (which will be logged
+            // anyway due to CommandBase.log)
+            if (auditLogType != null && auditLogType != 
AuditLogType.USER_VDC_LOGIN_FAILED) {
+                logEventForUser(user, auditLogType);
+            }
+
+            if (authResult == Authn.AuthResult.CREDENTIALS_EXPIRED) {
+                boolean addedUserPasswordExpiredCDA = false;
+                if (outputMap.<String> 
get(Authn.InvokeKeys.CREDENTIALS_CHANGE_URL) != null) {
+                    
addCanDoActionMessage(VdcBllMessages.USER_PASSWORD_EXPIRED_CHANGE_URL_PROVIDED);
+                    
getReturnValue().getCanDoActionMessages().add(String.format("$URL %1$s",
+                            outputMap.<String> 
get(Authn.InvokeKeys.CREDENTIALS_CHANGE_URL)));
+                    addedUserPasswordExpiredCDA = true;
+                }
+                if (outputMap.<String> get(Authn.InvokeKeys.USER_MESSAGE) != 
null) {
+                    
addCanDoActionMessage(VdcBllMessages.USER_PASSWORD_EXPIRED_CHANGE_MSG_PROVIDED);
+                    
getReturnValue().getCanDoActionMessages().add(String.format("$MSG %1$s",
+                            outputMap.<String> 
get(Authn.InvokeKeys.USER_MESSAGE)));
+                    addedUserPasswordExpiredCDA = true;
+                }
+                if (!addedUserPasswordExpiredCDA) {
+                    
addCanDoActionMessage(VdcBllMessages.USER_PASSWORD_EXPIRED);
+                }
+            } else {
+                addCanDoActionMessage(vdcBllMessagesMap.get(authResult));
+            }
+            result = false;
+        }
+        return result;
+    }
+
 }


-- 
To view, visit http://gerrit.ovirt.org/26602
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I916012eab61a96bdb0f366d9dc8462325d7f726f
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: master
Gerrit-Owner: Yair Zaslavsky <yzasl...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to