Piotr Kliczewski has uploaded a new change for review.

Change subject: core: protocol fall back for older vdsms
......................................................................

core: protocol fall back for older vdsms

When we try to install new host which only supports xmlrpc and we have
cluster with compatibility level set to 3.5+ the code will fail.
Solution for this issue is attempting to connect by using jsonrpc and if
it fails falling back to xmlrpc.


Bug-Url: https://bugzilla.redhat.com/1149655
Change-Id: Ie6f48bec60b520c089f326f8c5e79aec288ff3d6
Signed-off-by: pkliczewski <piotr.kliczew...@gmail.com>
---
M 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/InstallVdsInternalCommand.java
A 
backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/transport/ProtocolDetector.java
M 
backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/vdscommands/FutureVDSCommandType.java
A 
backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/vdscommands/TimeBoundPollVDSCommandParameters.java
M 
backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/jsonrpc/FutureMap.java
M 
backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/jsonrpc/JsonRpcVdsServer.java
M 
backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/vdsbroker/IVdsServer.java
A 
backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/vdsbroker/TimeBoundPollVDSCommand.java
M 
backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/vdsbroker/VdsServerWrapper.java
9 files changed, 211 insertions(+), 3 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/98/34098/1

diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/InstallVdsInternalCommand.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/InstallVdsInternalCommand.java
index 7b4a58e..eeb07be 100644
--- 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/InstallVdsInternalCommand.java
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/InstallVdsInternalCommand.java
@@ -6,6 +6,7 @@
 import org.apache.commons.lang.StringUtils;
 import org.ovirt.engine.core.bll.context.CommandContext;
 import org.ovirt.engine.core.bll.network.NetworkConfigurator;
+import org.ovirt.engine.core.bll.transport.ProtocolDetector;
 import org.ovirt.engine.core.common.AuditLogType;
 import org.ovirt.engine.core.common.FeatureSupported;
 import org.ovirt.engine.core.common.action.InstallVdsParameters;
@@ -14,7 +15,9 @@
 import 
org.ovirt.engine.core.common.businessentities.OpenstackNetworkProviderProperties;
 import org.ovirt.engine.core.common.businessentities.Provider;
 import org.ovirt.engine.core.common.businessentities.ProviderType;
+import org.ovirt.engine.core.common.businessentities.VDS;
 import org.ovirt.engine.core.common.businessentities.VDSStatus;
+import org.ovirt.engine.core.common.businessentities.VdsProtocol;
 import org.ovirt.engine.core.common.errors.VdcBllMessages;
 import org.ovirt.engine.core.common.locks.LockingGroup;
 import org.ovirt.engine.core.common.utils.Pair;
@@ -160,6 +163,19 @@
                     RunSleepOnReboot(getStatusOnReboot());
                 break;
                 case Complete:
+                    if (checkProtocolTofallback(getVds())) {
+                        // we need to check whether we are connecting to vdsm 
which supports xmlrpc only
+                        ProtocolDetector detector = new 
ProtocolDetector(getVds());
+                        if (!detector.attemptConnection()) {
+                            detector.stopConnection();
+                            if (detector.attemptFallbackProtocol()) {
+                                detector.setFallbackProtocol();
+                            } else {
+                                detector.stopConnection();
+                                throw new 
VdsInstallException(VDSStatus.InstallFailed, "Host not reachable");
+                            }
+                        }
+                    }
                     if (!configureNetworkUsingHostDeploy) {
                         configureManagementNetwork();
                     }
@@ -184,6 +200,10 @@
         }
     }
 
+    private boolean checkProtocolTofallback(VDS vds) {
+        return VdsProtocol.STOMP.equals(vds.getProtocol());
+    }
+
     private void configureManagementNetwork() {
         final NetworkConfigurator networkConfigurator = new 
NetworkConfigurator(getVds(), getContext());
         if (!networkConfigurator.awaitVdsmResponse()) {
diff --git 
a/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/transport/ProtocolDetector.java
 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/transport/ProtocolDetector.java
new file mode 100644
index 0000000..d24a1be
--- /dev/null
+++ 
b/backend/manager/modules/bll/src/main/java/org/ovirt/engine/core/bll/transport/ProtocolDetector.java
@@ -0,0 +1,89 @@
+package org.ovirt.engine.core.bll.transport;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.ovirt.engine.core.bll.Backend;
+import org.ovirt.engine.core.common.businessentities.VDS;
+import org.ovirt.engine.core.common.businessentities.VdsProtocol;
+import org.ovirt.engine.core.common.businessentities.VdsStatic;
+import org.ovirt.engine.core.common.config.Config;
+import org.ovirt.engine.core.common.config.ConfigValues;
+import org.ovirt.engine.core.common.interfaces.FutureVDSCall;
+import org.ovirt.engine.core.common.vdscommands.FutureVDSCommandType;
+import 
org.ovirt.engine.core.common.vdscommands.TimeBoundPollVDSCommandParameters;
+import org.ovirt.engine.core.common.vdscommands.VDSReturnValue;
+import org.ovirt.engine.core.dal.dbbroker.DbFacade;
+import org.ovirt.engine.core.utils.transaction.TransactionMethod;
+import org.ovirt.engine.core.utils.transaction.TransactionSupport;
+import org.ovirt.engine.core.vdsbroker.ResourceManager;
+
+/**
+ * We need to detect whether vdsm supports jsonrpc or only xmlrpc. It is 
confusing to users
+ * when they have cluster 3.5+ and connect to vdsm <3.5 which supports only 
xmlrpc.
+ * In order to present version information in such situation we need fallback 
to xmlrpc.
+ *
+ */
+public class ProtocolDetector {
+
+    private VDS vds;
+
+    public ProtocolDetector(VDS vds) {
+        this.vds = vds;
+    }
+
+    /**
+     * Attempts to connect to vdsm using a proxy from {@code VdsManager} for a 
host.
+     *
+     * @return <code>true</code> if connected or <code>false</code> if 
connection failed.
+     */
+    public boolean attemptConnection() {
+        try {
+            long timeout = Config.<Integer> 
getValue(ConfigValues.SetupNetworksPollingTimeout);
+            FutureVDSCall<VDSReturnValue> task =
+                    
Backend.getInstance().getResourceManager().runFutureVdsCommand(FutureVDSCommandType.TimeBoundPoll,
+                            new TimeBoundPollVDSCommandParameters(vds.getId(), 
timeout, TimeUnit.SECONDS));
+            VDSReturnValue returnValue =
+                    task.get(timeout, TimeUnit.SECONDS);
+
+            if (returnValue.getSucceeded()) {
+                return true;
+            }
+        } catch (TimeoutException ignored) {
+        }
+        return false;
+    }
+
+    /**
+     * Stops {@code VdsManager} for a host.
+     */
+    public void stopConnection() {
+        ResourceManager.getInstance().RemoveVds(this.vds.getId());
+    }
+
+    /**
+     * Fall back the protocol and attempts the connection {@link 
ProtocolDetector#attemptConnection()}.
+     *
+     * @return <code>true</code> if connected or <code>false</code> if 
connection failed.
+     */
+    public boolean attemptFallbackProtocol() {
+        vds.setProtocol(VdsProtocol.XML);
+        ResourceManager.getInstance().AddVds(vds, false);
+        return attemptConnection();
+    }
+
+    /**
+     * Updates DB with fall back protocol (xmlrpc).
+     */
+    public void setFallbackProtocol() {
+        final VdsStatic vdsStatic = this.vds.getStaticData();
+        vdsStatic.setProtocol(VdsProtocol.XML);
+        TransactionSupport.executeInNewTransaction(new 
TransactionMethod<Void>() {
+            @Override
+            public Void runInTransaction() {
+                DbFacade.getInstance().getVdsStaticDao().update(vdsStatic);
+                return null;
+            }
+        });
+    }
+}
diff --git 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/vdscommands/FutureVDSCommandType.java
 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/vdscommands/FutureVDSCommandType.java
index e90c07d..59c74fa 100644
--- 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/vdscommands/FutureVDSCommandType.java
+++ 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/vdscommands/FutureVDSCommandType.java
@@ -2,7 +2,8 @@
 
 public enum FutureVDSCommandType {
     SetupNetworks,
-    Poll;
+    Poll,
+    TimeBoundPoll;
 
     private static final String DEFAULT_PACKAGE = 
"org.ovirt.engine.core.vdsbroker.vdsbroker";
     String packageName;
diff --git 
a/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/vdscommands/TimeBoundPollVDSCommandParameters.java
 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/vdscommands/TimeBoundPollVDSCommandParameters.java
new file mode 100644
index 0000000..5f7307e
--- /dev/null
+++ 
b/backend/manager/modules/common/src/main/java/org/ovirt/engine/core/common/vdscommands/TimeBoundPollVDSCommandParameters.java
@@ -0,0 +1,28 @@
+package org.ovirt.engine.core.common.vdscommands;
+
+import java.util.concurrent.TimeUnit;
+
+import org.ovirt.engine.core.compat.Guid;
+
+public class TimeBoundPollVDSCommandParameters extends 
VdsIdVDSCommandParametersBase {
+    private long timeout;
+    private TimeUnit unit;
+
+    public TimeBoundPollVDSCommandParameters() {
+    }
+
+    public TimeBoundPollVDSCommandParameters(Guid vdsId, long timeout, 
TimeUnit unit) {
+        super(vdsId);
+        this.timeout = timeout;
+        this.unit = unit;
+    }
+
+    public long getTimeout() {
+        return timeout;
+    }
+
+    public TimeUnit getUnit() {
+        return unit;
+    }
+
+}
diff --git 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/jsonrpc/FutureMap.java
 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/jsonrpc/FutureMap.java
index 3a236ef..54a12c5 100644
--- 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/jsonrpc/FutureMap.java
+++ 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/jsonrpc/FutureMap.java
@@ -44,9 +44,17 @@
             super.put("code", 0);
         }
     };
+    private Map<String, Object> timeoutStatus = new HashMap<String, Object>() {
+        {
+            super.put("message", "Internal timeout occured");
+            super.put("code", -1);
+        }
+    };
     private Class<?> clazz = new HashMap<String, Object>().getClass();
     private Class<?> subTypeClazz;
     private boolean ignoreResponseKey = false;
+    private long timeout = 0;
+    private TimeUnit unit = TimeUnit.MILLISECONDS;
 
     /**
      * During creation request is sent and <code>Future</code> for a response 
is held.
@@ -64,6 +72,25 @@
     }
 
     /**
+     * During creation request is sent and <code>Future</code> for a response 
is held.
+     *
+     * @param client - Client object used to send request.
+     * @param request - Request to be sent.
+     * @param timeout - Timeout which is used when populating response map.
+     * @param unit - Time unit for timeout.
+     * @throws XmlRpcRunTimeException when there are connection issues.
+     */
+    public FutureMap(JsonRpcClient client, JsonRpcRequest request, long 
timeout, TimeUnit unit) {
+        try {
+            this.timeout = timeout;
+            this.unit = unit;
+            this.response = client.call(request);
+        } catch (ClientConnectionException e) {
+            throw new XmlRpcRunTimeException("Connection issues during send 
request", e);
+        }
+    }
+
+    /**
      * Whenever any method is executed to obtain value of response during the 
first invocation it gets real response
      * from the <code>Future</code> and decompose it to object of provided 
type and structure.
      *
@@ -73,10 +100,16 @@
         try (LockWrapper wrapper = new LockWrapper(this.lock)) {
             if (this.responseMap.isEmpty()) {
                 try {
-                    populate(this.response.get());
+                    if (timeout != 0) {
+                        populate(this.response.get(timeout, unit));
+                    } else {
+                        populate(this.response.get());
+                    }
                 } catch (InterruptedException | ExecutionException e) {
                     log.error("Exception occured during response 
decomposition", e);
                     throw new IllegalStateException(e);
+                } catch (TimeoutException e) {
+                    this.responseMap.put(STATUS, timeoutStatus);
                 }
             }
         }
diff --git 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/jsonrpc/JsonRpcVdsServer.java
 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/jsonrpc/JsonRpcVdsServer.java
index 0fee690..59c249c 100644
--- 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/jsonrpc/JsonRpcVdsServer.java
+++ 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/jsonrpc/JsonRpcVdsServer.java
@@ -7,6 +7,7 @@
 import java.util.concurrent.Callable;
 import java.util.concurrent.Future;
 import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.httpclient.HttpClient;
 import org.ovirt.engine.core.compat.Guid;
@@ -909,12 +910,17 @@
 
     @Override
     public FutureTask<Map<String, Object>> poll() {
+        return timeBoundPoll(0, TimeUnit.MILLISECONDS);
+    }
+
+    @Override
+    public FutureTask<Map<String, Object>> timeBoundPoll(final long timeout, 
final TimeUnit unit) {
         final JsonRpcRequest request = new RequestBuilder("Host.ping").build();
         final FutureCallable callable = new FutureCallable(new 
Callable<Map<String, Object>>() {
 
             @Override
             public Map<String, Object> call() throws Exception {
-                return new FutureMap(client, request);
+                return new FutureMap(client, request, timeout, unit);
             }
         });
 
diff --git 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/vdsbroker/IVdsServer.java
 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/vdsbroker/IVdsServer.java
index 478a05b..839efd4 100644
--- 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/vdsbroker/IVdsServer.java
+++ 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/vdsbroker/IVdsServer.java
@@ -3,6 +3,7 @@
 import java.util.Map;
 import java.util.concurrent.Future;
 import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.httpclient.HttpClient;
 import org.ovirt.engine.core.compat.Guid;
@@ -185,6 +186,8 @@
 
     FutureTask<Map<String, Object>> poll();
 
+    FutureTask<Map<String, Object>> timeBoundPoll(long timeout, TimeUnit unit);
+
     StatusOnlyReturnForXmlRpc snapshot(String vmId, Map<String, String>[] 
disks);
 
     StatusOnlyReturnForXmlRpc snapshot(String vmId, Map<String, String>[] 
disks, String memory);
diff --git 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/vdsbroker/TimeBoundPollVDSCommand.java
 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/vdsbroker/TimeBoundPollVDSCommand.java
new file mode 100644
index 0000000..a19b69d
--- /dev/null
+++ 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/vdsbroker/TimeBoundPollVDSCommand.java
@@ -0,0 +1,22 @@
+package org.ovirt.engine.core.vdsbroker.vdsbroker;
+
+import 
org.ovirt.engine.core.common.vdscommands.TimeBoundPollVDSCommandParameters;
+import org.ovirt.engine.core.utils.log.Logged;
+import org.ovirt.engine.core.utils.log.Logged.LogLevel;
+
+/**
+ * Sole purpose of this command is to check connectivity with VDSM by invoking 
poll verb.
+ */
+@Logged(executionLevel = LogLevel.TRACE, errorLevel = LogLevel.DEBUG)
+public class TimeBoundPollVDSCommand<P extends 
TimeBoundPollVDSCommandParameters> extends FutureVDSCommand<P> {
+
+    public TimeBoundPollVDSCommand(P parameters) {
+        super(parameters);
+    }
+
+    @Override
+    protected void executeVdsBrokerCommand() {
+        httpTask = 
getBroker().timeBoundPoll(this.getParameters().getTimeout(), 
this.getParameters().getUnit());
+    }
+
+}
diff --git 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/vdsbroker/VdsServerWrapper.java
 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/vdsbroker/VdsServerWrapper.java
index a061795..14e49c1 100644
--- 
a/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/vdsbroker/VdsServerWrapper.java
+++ 
b/backend/manager/modules/vdsbroker/src/main/java/org/ovirt/engine/core/vdsbroker/vdsbroker/VdsServerWrapper.java
@@ -4,6 +4,7 @@
 import java.util.Map;
 import java.util.concurrent.Future;
 import java.util.concurrent.FutureTask;
+import java.util.concurrent.TimeUnit;
 
 import org.apache.commons.httpclient.HttpClient;
 import org.ovirt.engine.core.compat.Guid;
@@ -860,6 +861,11 @@
     }
 
     @Override
+    public FutureTask<Map<String, Object>> timeBoundPoll(long timeout, 
TimeUnit unit) {
+        return poll();
+    }
+
+    @Override
     public StatusOnlyReturnForXmlRpc snapshot(String vmId, Map<String, 
String>[] disks) {
         try {
             Map<String, Object> xmlRpcReturnValue = vdsServer.snapshot(vmId, 
disks);


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

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ie6f48bec60b520c089f326f8c5e79aec288ff3d6
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: ovirt-engine-3.5
Gerrit-Owner: Piotr Kliczewski <piotr.kliczew...@gmail.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to