This is an automated email from the ASF dual-hosted git repository.

rohit pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/main by this push:
     new 07cabbe  scaleio: Updated PowerFlex/ScaleIO gateway client with some 
improvements. (#5037)
07cabbe is described below

commit 07cabbe7ac4379a69591db88e3ad4f0b7f0d095f
Author: sureshanaparti <[email protected]>
AuthorDate: Wed Jun 16 12:45:27 2021 +0530

    scaleio: Updated PowerFlex/ScaleIO gateway client with some improvements. 
(#5037)
    
    - Added connection manager to the gateway client.
     - Renew the client session on '401 Unauthorized' response.
     - Refactored the gateway client calls, for GET and POST methods.
     - Consume the http entity content after login/(re)authentication and close 
the content stream if exists.
     - Updated storage pool client connection timeout configuration 
'storage.pool.client.timeout' to non-dynamic.
     - Added storage pool client max connections configuration 
'storage.pool.client.max.connections' (default: 100) to specify the maximum 
connections for the ScaleIO storage pool client.
     - Updated unit tests.
    and blocked the attach volume operation for uploaded volume on 
ScaleIO/PowerFlex storage pool
---
 .../java/com/cloud/storage/StorageManager.java     |  11 +-
 plugins/storage/volume/scaleio/pom.xml             |   6 +
 .../datastore/client/ScaleIOGatewayClient.java     |   4 +-
 .../client/ScaleIOGatewayClientConnectionPool.java |   3 +-
 .../datastore/client/ScaleIOGatewayClientImpl.java | 981 +++++++++------------
 .../ScaleIOPrimaryDataStoreLifeCycle.java          |   7 +-
 .../client/ScaleIOGatewayClientImplTest.java       | 157 +++-
 .../configuration/ConfigurationManagerImpl.java    |   3 +
 .../java/com/cloud/storage/StorageManagerImpl.java |   1 +
 .../com/cloud/storage/VolumeApiServiceImpl.java    |  11 +
 10 files changed, 600 insertions(+), 584 deletions(-)

diff --git 
a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java 
b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
index db41a2f..96cf333 100644
--- a/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
+++ b/engine/components-api/src/main/java/com/cloud/storage/StorageManager.java
@@ -124,7 +124,16 @@ public interface StorageManager extends StorageService {
             "Storage",
             "60",
             "Timeout (in secs) for the storage pool client connection timeout 
(for managed pools). Currently only supported for PowerFlex.",
-            true,
+            false,
+            ConfigKey.Scope.StoragePool,
+            null);
+
+    ConfigKey<Integer> STORAGE_POOL_CLIENT_MAX_CONNECTIONS = new 
ConfigKey<>(Integer.class,
+            "storage.pool.client.max.connections",
+            "Storage",
+            "100",
+            "Maximum connections for the storage pool client (for managed 
pools). Currently only supported for PowerFlex.",
+            false,
             ConfigKey.Scope.StoragePool,
             null);
 
diff --git a/plugins/storage/volume/scaleio/pom.xml 
b/plugins/storage/volume/scaleio/pom.xml
index e95087e..36a385c 100644
--- a/plugins/storage/volume/scaleio/pom.xml
+++ b/plugins/storage/volume/scaleio/pom.xml
@@ -33,6 +33,12 @@
             <artifactId>cloud-engine-storage-volume</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>com.github.tomakehurst</groupId>
+            <artifactId>wiremock-standalone</artifactId>
+            <version>${cs.wiremock.version}</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git 
a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClient.java
 
b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClient.java
index f6b10f8..f497b10 100644
--- 
a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClient.java
+++ 
b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClient.java
@@ -40,8 +40,8 @@ public interface ScaleIOGatewayClient {
     String STORAGE_POOL_SYSTEM_ID = "powerflex.storagepool.system.id";
 
     static ScaleIOGatewayClient getClient(final String url, final String 
username, final String password,
-                                          final boolean validateCertificate, 
final int timeout) throws NoSuchAlgorithmException, KeyManagementException, 
URISyntaxException {
-        return new ScaleIOGatewayClientImpl(url, username, password, 
validateCertificate, timeout);
+                                          final boolean validateCertificate, 
final int timeout, final int maxConnections) throws NoSuchAlgorithmException, 
KeyManagementException, URISyntaxException {
+        return new ScaleIOGatewayClientImpl(url, username, password, 
validateCertificate, timeout, maxConnections);
     }
 
     // Volume APIs
diff --git 
a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientConnectionPool.java
 
b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientConnectionPool.java
index 2daf8e4..e557e08 100644
--- 
a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientConnectionPool.java
+++ 
b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientConnectionPool.java
@@ -62,8 +62,9 @@ public class ScaleIOGatewayClientConnectionPool {
                 final String encryptedPassword = 
storagePoolDetailsDao.findDetail(storagePoolId, 
ScaleIOGatewayClient.GATEWAY_API_PASSWORD).getValue();
                 final String password = 
DBEncryptionUtil.decrypt(encryptedPassword);
                 final int clientTimeout = 
StorageManager.STORAGE_POOL_CLIENT_TIMEOUT.valueIn(storagePoolId);
+                final int clientMaxConnections = 
StorageManager.STORAGE_POOL_CLIENT_MAX_CONNECTIONS.valueIn(storagePoolId);
 
-                client = new ScaleIOGatewayClientImpl(url, username, password, 
false, clientTimeout);
+                client = new ScaleIOGatewayClientImpl(url, username, password, 
false, clientTimeout, clientMaxConnections);
                 gatewayClients.put(storagePoolId, client);
                 LOGGER.debug("Added gateway client for the storage pool: " + 
storagePoolId);
             }
diff --git 
a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImpl.java
 
b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImpl.java
index 5e8568d..fa19541 100644
--- 
a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImpl.java
+++ 
b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImpl.java
@@ -56,11 +56,16 @@ import org.apache.http.client.HttpClient;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
 import org.apache.http.conn.ConnectTimeoutException;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
 import org.apache.http.conn.ssl.NoopHostnameVerifier;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.pool.PoolStats;
 import org.apache.http.util.EntityUtils;
 import org.apache.log4j.Logger;
 
@@ -80,25 +85,27 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
 
     private final URI apiURI;
     private final HttpClient httpClient;
-    private static final String SESSION_HEADER = "X-RestSvcSessionId";
+    private final PoolingHttpClientConnectionManager connectionManager;
     private static final String MDM_CONNECTED_STATE = "Connected";
 
-    private String host;
     private String username;
     private String password;
     private String sessionKey = null;
 
     // The session token is valid for 8 hours from the time it was created, 
unless there has been no activity for 10 minutes
     // Reference: 
https://cpsdocs.dellemc.com/bundle/PF_REST_API_RG/page/GUID-92430F19-9F44-42B6-B898-87D5307AE59B.html
-    private static final long MAX_VALID_SESSION_TIME_IN_MILLISECS = 8 * 60 * 
60 * 1000; // 8 hrs
-    private static final long MAX_IDLE_TIME_IN_MILLISECS = 10 * 60 * 1000; // 
10 mins
+    private static final long MAX_VALID_SESSION_TIME_IN_HRS = 8;
+    private static final long MAX_VALID_SESSION_TIME_IN_MILLISECS = 
MAX_VALID_SESSION_TIME_IN_HRS * 60 * 60 * 1000;
+    private static final long MAX_IDLE_TIME_IN_MINS = 10;
+    private static final long MAX_IDLE_TIME_IN_MILLISECS = 
MAX_IDLE_TIME_IN_MINS * 60 * 1000;
     private static final long BUFFER_TIME_IN_MILLISECS = 30 * 1000; // keep 30 
secs buffer before the expiration (to avoid any last-minute operations)
 
+    private boolean authenticating = false;
     private long createTime = 0;
     private long lastUsedTime = 0;
 
     public ScaleIOGatewayClientImpl(final String url, final String username, 
final String password,
-                                    final boolean validateCertificate, final 
int timeout)
+                                    final boolean validateCertificate, final 
int timeout, final int maxConnections)
             throws NoSuchAlgorithmException, KeyManagementException, 
URISyntaxException {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(url), "Gateway 
client url cannot be null");
         Preconditions.checkArgument(!Strings.isNullOrEmpty(username) && 
!Strings.isNullOrEmpty(password), "Gateway client credentials cannot be null");
@@ -109,83 +116,141 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
                 .setSocketTimeout(timeout * 1000)
                 .build();
 
+        SSLConnectionSocketFactory factory = 
SSLConnectionSocketFactory.getSocketFactory();
         if (!validateCertificate) {
             final SSLContext sslcontext = SSLUtils.getSSLContext();
             sslcontext.init(null, new X509TrustManager[]{new 
TrustAllManager()}, new SecureRandom());
-            final SSLConnectionSocketFactory factory = new 
SSLConnectionSocketFactory(sslcontext, NoopHostnameVerifier.INSTANCE);
-            this.httpClient = HttpClientBuilder.create()
-                    .setDefaultRequestConfig(config)
-                    .setSSLSocketFactory(factory)
-                    .build();
-        } else {
-            this.httpClient = HttpClientBuilder.create()
-                    .setDefaultRequestConfig(config)
-                    .build();
+            factory = new SSLConnectionSocketFactory(sslcontext, 
NoopHostnameVerifier.INSTANCE);
         }
 
+        final Registry<ConnectionSocketFactory> socketFactoryRegistry = 
RegistryBuilder.<ConnectionSocketFactory> create()
+                .register("https", factory)
+                .build();
+        connectionManager = new 
PoolingHttpClientConnectionManager(socketFactoryRegistry);
+        connectionManager.setMaxTotal(maxConnections);
+        connectionManager.setDefaultMaxPerRoute(maxConnections);
+
+        this.httpClient = HttpClientBuilder.create()
+                .setConnectionManager(connectionManager)
+                .setDefaultRequestConfig(config)
+                .setSSLSocketFactory(factory)
+                .build();
+
         this.apiURI = new URI(url);
-        this.host = apiURI.getHost();
         this.username = username;
         this.password = password;
 
         authenticate();
+        LOG.debug("API client for the PowerFlex gateway " + apiURI.getHost() + 
" is created successfully, with max connections: "
+                + maxConnections + " and timeout: " + timeout + " secs");
     }
 
     /////////////////////////////////////////////////////////////
     //////////////// Private Helper Methods /////////////////////
     /////////////////////////////////////////////////////////////
 
-    private void authenticate() {
+    private synchronized void authenticate() {
         final HttpGet request = new HttpGet(apiURI.toString() + "/login");
         request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + 
Base64.getEncoder().encodeToString((username + ":" + password).getBytes()));
+        HttpResponse response = null;
         try {
-            final HttpResponse response = httpClient.execute(request);
-            checkAuthFailure(response);
-            this.sessionKey = EntityUtils.toString(response.getEntity());
-            if (Strings.isNullOrEmpty(this.sessionKey)) {
-                throw new CloudRuntimeException("Failed to create a valid 
PowerFlex Gateway Session to perform API requests");
+            authenticating = true;
+            LOG.debug("Authenticating gateway " + apiURI.getHost() + " with 
the request: " + request.toString());
+            response = httpClient.execute(request);
+            if (isNullResponse(response)) {
+                LOG.warn("Invalid response received while authenticating, for 
the request: " + request.toString());
+                throw new CloudRuntimeException("Failed to authenticate 
PowerFlex API Gateway due to invalid response from the Gateway " + 
apiURI.getHost());
             }
-            this.sessionKey = this.sessionKey.replace("\"", "");
+
+            LOG.debug("Received response: " + 
response.getStatusLine().getStatusCode() + " " + 
response.getStatusLine().getReasonPhrase()
+                    + ", for the authenticate request: " + request.toString());
             if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
-                throw new CloudRuntimeException("PowerFlex Gateway login 
failed, please check the provided settings");
+                throw new CloudRuntimeException("PowerFlex Gateway " + 
apiURI.getHost() + " login failed, please check the provided settings");
             }
+
+            String sessionKeyInResponse = 
EntityUtils.toString(response.getEntity());
+            if (Strings.isNullOrEmpty(sessionKeyInResponse)) {
+                throw new CloudRuntimeException("Failed to create a valid 
session for PowerFlex Gateway " + apiURI.getHost() + " to perform API 
requests");
+            }
+
+            LOG.info("PowerFlex API Gateway " + apiURI.getHost() + " 
authenticated successfully");
+            this.sessionKey = sessionKeyInResponse.replace("\"", "");
+
+            long now = System.currentTimeMillis();
+            createTime = lastUsedTime = now;
         } catch (final IOException e) {
-            throw new CloudRuntimeException("Failed to authenticate PowerFlex 
API Gateway due to:" + e.getMessage());
+            LOG.error("Failed to authenticate PowerFlex API Gateway " + 
apiURI.getHost() + " due to: " + e.getMessage() + getConnectionManagerStats());
+            throw new CloudRuntimeException("Failed to authenticate PowerFlex 
API Gateway " + apiURI.getHost() + " due to: " + e.getMessage());
+        } finally {
+            authenticating = false;
+            if (response != null) {
+                EntityUtils.consumeQuietly(response.getEntity());
+            }
         }
-        long now = System.currentTimeMillis();
-        createTime = lastUsedTime = now;
     }
 
     private synchronized void renewClientSessionOnExpiry() {
         if (isSessionExpired()) {
-            LOG.debug("Session expired, renewing");
+            LOG.debug("Session expired for the PowerFlex API Gateway " + 
apiURI.getHost() + ", renewing");
             authenticate();
         }
     }
 
     private boolean isSessionExpired() {
         long now = System.currentTimeMillis() + BUFFER_TIME_IN_MILLISECS;
-        if ((now - createTime) > MAX_VALID_SESSION_TIME_IN_MILLISECS ||
-                (now - lastUsedTime) > MAX_IDLE_TIME_IN_MILLISECS) {
+        if ((now - createTime) > MAX_VALID_SESSION_TIME_IN_MILLISECS) {
+            LOG.debug("Session expired for the Gateway " + apiURI.getHost() + 
", token is invalid after " + MAX_VALID_SESSION_TIME_IN_HRS
+                    + " hours from the time it was created");
+            return true;
+        }
+
+        if ((now - lastUsedTime) > MAX_IDLE_TIME_IN_MILLISECS) {
+            LOG.debug("Session expired for the Gateway " + apiURI.getHost() + 
", as there has been no activity for " + MAX_IDLE_TIME_IN_MINS + " mins");
             return true;
         }
+
         return false;
     }
 
-    private void checkAuthFailure(final HttpResponse response) {
-        if (response != null && response.getStatusLine().getStatusCode() == 
HttpStatus.SC_UNAUTHORIZED) {
-            throw new ServerApiException(ApiErrorCode.UNAUTHORIZED, "PowerFlex 
Gateway API call unauthorized, please check the provided settings");
+    private boolean isNullResponse(final HttpResponse response) {
+        if (response == null) {
+            LOG.warn("Nil response");
+            return true;
+        }
+
+        if (response.getStatusLine() == null) {
+            LOG.warn("No status line in the response");
+            return true;
         }
+
+        return false;
+    }
+
+    private boolean checkAuthFailure(final HttpResponse response, final 
boolean renewAndRetryOnAuthFailure) {
+        if (!isNullResponse(response) && 
response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
+            if (!renewAndRetryOnAuthFailure) {
+                throw new ServerApiException(ApiErrorCode.UNAUTHORIZED, 
"PowerFlex Gateway API call unauthorized, please check the provided settings");
+            }
+            LOG.debug("PowerFlex Gateway API call unauthorized. Current token 
might be invalid, renew the session." + getConnectionManagerStats());
+            return true;
+        }
+        return false;
     }
 
     private void checkResponseOK(final HttpResponse response) {
+        if (isNullResponse(response)) {
+            return;
+        }
+
         if (response.getStatusLine().getStatusCode() == 
HttpStatus.SC_NO_CONTENT) {
-            LOG.debug("Requested resource does not exist");
+            LOG.warn("Requested resource does not exist");
             return;
         }
+
         if (response.getStatusLine().getStatusCode() == 
HttpStatus.SC_BAD_REQUEST) {
             throw new 
ServerApiException(ApiErrorCode.MALFORMED_PARAMETER_ERROR, "Bad API request");
         }
+
         if (!(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK ||
                 response.getStatusLine().getStatusCode() == 
HttpStatus.SC_ACCEPTED)) {
             String responseBody = response.toString();
@@ -193,54 +258,118 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
                 responseBody = EntityUtils.toString(response.getEntity());
             } catch (IOException ignored) {
             }
-            LOG.debug("HTTP request failed, status code is " + 
response.getStatusLine().getStatusCode() + ", response is: " + responseBody);
+            LOG.debug("HTTP request failed, status code: " + 
response.getStatusLine().getStatusCode() + ", response: "
+                    + responseBody + getConnectionManagerStats());
             throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "API 
failed due to: " + responseBody);
         }
     }
 
     private void checkResponseTimeOut(final Exception e) {
         if (e instanceof ConnectTimeoutException || e instanceof 
SocketTimeoutException) {
-            throw new 
ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, "API operation 
timed out, please try again.");
+            throw new 
ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, "Gateway API 
operation timed out, please try again.");
         }
     }
 
-    private HttpResponse get(final String path) throws IOException {
+    private <T> T get(final String path, final Class<T> type) {
+        return get(path, type, true);
+    }
+
+    private <T> T get(final String path, final Class<T> type, final boolean 
renewAndRetryOnAuthFailure) {
         renewClientSessionOnExpiry();
-        final HttpGet request = new HttpGet(apiURI.toString() + path);
-        request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + 
Base64.getEncoder().encodeToString((this.username + ":" + 
this.sessionKey).getBytes()));
-        final HttpResponse response = httpClient.execute(request);
-        synchronized (this) {
-            lastUsedTime = System.currentTimeMillis();
+        HttpResponse response = null;
+        boolean responseConsumed = false;
+        try {
+            while (authenticating); // wait for authentication request (if 
any) to complete (and to pick the new session key)
+            final HttpGet request = new HttpGet(apiURI.toString() + path);
+            request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + 
Base64.getEncoder().encodeToString((this.username + ":" + 
this.sessionKey).getBytes()));
+            LOG.debug("Sending GET request: " + request.toString());
+            response = httpClient.execute(request);
+            String responseStatus = (!isNullResponse(response)) ? 
(response.getStatusLine().getStatusCode() + " " + 
response.getStatusLine().getReasonPhrase()) : "nil";
+            LOG.debug("Received response: " + responseStatus + ", for the sent 
GET request: " + request.toString());
+            if (checkAuthFailure(response, renewAndRetryOnAuthFailure)) {
+                EntityUtils.consumeQuietly(response.getEntity());
+                responseConsumed = true;
+
+                authenticate();
+                return get(path, type, false);
+            }
+            return processResponse(response, type);
+        }  catch (final IOException e) {
+            LOG.error("Failed in GET method due to: " + e.getMessage() + 
getConnectionManagerStats(), e);
+            checkResponseTimeOut(e);
+        } finally {
+            if (!responseConsumed && response != null) {
+                EntityUtils.consumeQuietly(response.getEntity());
+            }
         }
-        String responseStatus = (response != null) ? 
(response.getStatusLine().getStatusCode() + " " + 
response.getStatusLine().getReasonPhrase()) : "nil";
-        LOG.debug("GET request path: " + path + ", response: " + 
responseStatus);
-        checkAuthFailure(response);
-        return response;
+        return null;
     }
 
-    private HttpResponse post(final String path, final Object obj) throws 
IOException {
+    private <T> T post(final String path, final Object obj, final Class<T> 
type) {
+        return post(path, obj, type, true);
+    }
+
+    private <T> T post(final String path, final Object obj, final Class<T> 
type, final boolean renewAndRetryOnAuthFailure) {
         renewClientSessionOnExpiry();
-        final HttpPost request = new HttpPost(apiURI.toString() + path);
-        request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + 
Base64.getEncoder().encodeToString((this.username + ":" + 
this.sessionKey).getBytes()));
-        request.setHeader("Content-type", "application/json");
-        if (obj != null) {
-            if (obj instanceof String) {
-                request.setEntity(new StringEntity((String) obj));
-            } else {
-                JsonMapper mapper = new JsonMapper();
-                mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
-                String json = mapper.writer().writeValueAsString(obj);
-                request.setEntity(new StringEntity(json));
+        HttpResponse response = null;
+        boolean responseConsumed = false;
+        try {
+            while (authenticating); // wait for authentication request (if 
any) to complete (and to pick the new session key)
+            final HttpPost request = new HttpPost(apiURI.toString() + path);
+            request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + 
Base64.getEncoder().encodeToString((this.username + ":" + 
this.sessionKey).getBytes()));
+            request.setHeader("Content-type", "application/json");
+            if (obj != null) {
+                if (obj instanceof String) {
+                    request.setEntity(new StringEntity((String) obj));
+                } else {
+                    JsonMapper mapper = new JsonMapper();
+                    
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
+                    String json = mapper.writer().writeValueAsString(obj);
+                    request.setEntity(new StringEntity(json));
+                }
+            }
+            LOG.debug("Sending POST request: " + request.toString());
+            response = httpClient.execute(request);
+            String responseStatus = (!isNullResponse(response)) ? 
(response.getStatusLine().getStatusCode() + " " + 
response.getStatusLine().getReasonPhrase()) : "nil";
+            LOG.debug("Received response: " + responseStatus + ", for the sent 
POST request: " + request.toString());
+            if (checkAuthFailure(response, renewAndRetryOnAuthFailure)) {
+                EntityUtils.consumeQuietly(response.getEntity());
+                responseConsumed = true;
+
+                authenticate();
+                return post(path, obj, type, false);
+            }
+            return processResponse(response, type);
+        } catch (final IOException e) {
+            LOG.error("Failed in POST method due to: " + e.getMessage() + 
getConnectionManagerStats(), e);
+            checkResponseTimeOut(e);
+        } finally {
+            if (!responseConsumed && response != null) {
+                EntityUtils.consumeQuietly(response.getEntity());
             }
         }
-        final HttpResponse response = httpClient.execute(request);
+        return null;
+    }
+
+    private <T> T processResponse(HttpResponse response, final Class<T> type) 
throws IOException {
+        if (isNullResponse(response)) {
+            return null;
+        }
+
+        checkResponseOK(response);
         synchronized (this) {
             lastUsedTime = System.currentTimeMillis();
         }
-        String responseStatus = (response != null) ? 
(response.getStatusLine().getStatusCode() + " " + 
response.getStatusLine().getReasonPhrase()) : "nil";
-        LOG.debug("POST request path: " + path + ", response: " + 
responseStatus);
-        checkAuthFailure(response);
-        return response;
+        if (type == Boolean.class) {
+            return (T) Boolean.TRUE;
+        } else if (type == String.class) {
+            return (T) EntityUtils.toString(response.getEntity());
+        } else if (type == JsonNode.class) {
+            return (T) new 
ObjectMapper().readTree(response.getEntity().getContent());
+        } else {
+            ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
+            return mapper.readValue(response.getEntity().getContent(), type);
+        }
     }
 
     //////////////////////////////////////////////////
@@ -254,50 +383,25 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(storagePoolId), 
"Storage pool id cannot be null");
         Preconditions.checkArgument(sizeInGb != null && sizeInGb > 0, 
"Size(GB) must be greater than 0");
 
-        HttpResponse response = null;
-        try {
-            Volume newVolume = new Volume();
-            newVolume.setName(name);
-            newVolume.setStoragePoolId(storagePoolId);
-            newVolume.setVolumeSizeInGb(sizeInGb);
-            if (Storage.ProvisioningType.FAT.equals(volumeType)) {
-                newVolume.setVolumeType(Volume.VolumeType.ThickProvisioned);
-            } else {
-                newVolume.setVolumeType(Volume.VolumeType.ThinProvisioned);
-            }
-            // The basic allocation granularity is 8GB. The volume size will 
be rounded up.
-            response = post("/types/Volume/instances", newVolume);
-            checkResponseOK(response);
-            ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
-            Volume newVolumeObject = 
mapper.readValue(response.getEntity().getContent(), Volume.class);
-            return getVolume(newVolumeObject.getId());
-        } catch (final IOException e) {
-            LOG.error("Failed to create PowerFlex volume due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
+        Volume newVolume = new Volume();
+        newVolume.setName(name);
+        newVolume.setStoragePoolId(storagePoolId);
+        newVolume.setVolumeSizeInGb(sizeInGb);
+        if (Storage.ProvisioningType.FAT.equals(volumeType)) {
+            newVolume.setVolumeType(Volume.VolumeType.ThickProvisioned);
+        } else {
+            newVolume.setVolumeType(Volume.VolumeType.ThinProvisioned);
         }
-        return null;
+        // The basic allocation granularity is 8GB. The volume size will be 
rounded up.
+        Volume newVolumeObject = post("/types/Volume/instances", newVolume, 
Volume.class);
+        return getVolume(newVolumeObject.getId());
     }
 
     @Override
     public List<Volume> listVolumes() {
-        HttpResponse response = null;
-        try {
-            response = get("/types/Volume/instances");
-            checkResponseOK(response);
-            ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
-            Volume[] volumes = 
mapper.readValue(response.getEntity().getContent(), Volume[].class);
+        Volume[] volumes = get("/types/Volume/instances", Volume[].class);
+        if (volumes != null) {
             return Arrays.asList(volumes);
-        } catch (final IOException e) {
-            LOG.error("Failed to list PowerFlex volumes due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
         }
         return new ArrayList<>();
     }
@@ -313,52 +417,24 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
                 }
             }
         }
-
         return snapshotVolumes;
     }
 
     @Override
     public Volume getVolume(String volumeId) {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume 
id cannot be null");
-
-        HttpResponse response = null;
-        try {
-            response = get("/instances/Volume::" + volumeId);
-            checkResponseOK(response);
-            ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
-            return mapper.readValue(response.getEntity().getContent(), 
Volume.class);
-        } catch (final IOException e) {
-            LOG.error("Failed to get volume due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
-        }
-        return null;
+        return get("/instances/Volume::" + volumeId, Volume.class);
     }
 
     @Override
     public Volume getVolumeByName(String name) {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(name), "Volume name 
cannot be null");
 
-        HttpResponse response = null;
-        try {
-            Volume searchVolume = new Volume();
-            searchVolume.setName(name);
-            response = post("/types/Volume/instances/action/queryIdByKey", 
searchVolume);
-            checkResponseOK(response);
-            String volumeId = EntityUtils.toString(response.getEntity());
-            if (!Strings.isNullOrEmpty(volumeId)) {
-                return getVolume(volumeId.replace("\"", ""));
-            }
-        } catch (final IOException e) {
-            LOG.error("Failed to get volume due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
+        Volume searchVolume = new Volume();
+        searchVolume.setName(name);
+        String volumeId = post("/types/Volume/instances/action/queryIdByKey", 
searchVolume, String.class);
+        if (!Strings.isNullOrEmpty(volumeId)) {
+            return getVolume(volumeId.replace("\"", ""));
         }
         return null;
     }
@@ -368,20 +444,11 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume 
id cannot be null");
         Preconditions.checkArgument(!Strings.isNullOrEmpty(newName), "New name 
for volume cannot be null");
 
-        HttpResponse response = null;
-        try {
-            response = post(
-                    "/instances/Volume::" + volumeId + "/action/setVolumeName",
-                    String.format("{\"newName\":\"%s\"}", newName));
-            checkResponseOK(response);
-            return true;
-        } catch (final IOException e) {
-            LOG.error("Failed to rename PowerFlex volume due to: ", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
+        Boolean renameVolumeStatus = post(
+                "/instances/Volume::" + volumeId + "/action/setVolumeName",
+                String.format("{\"newName\":\"%s\"}", newName), Boolean.class);
+        if (renameVolumeStatus != null) {
+            return renameVolumeStatus;
         }
         return false;
     }
@@ -392,21 +459,12 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
         Preconditions.checkArgument(sizeInGB != null && (sizeInGB > 0 && 
sizeInGB % 8 == 0),
                 "Size(GB) must be greater than 0 and in granularity of 8");
 
-        HttpResponse response = null;
-        try {
-            // Volume capacity can only be increased. sizeInGB must be a 
positive number in granularity of 8 GB.
-            response = post(
-                    "/instances/Volume::" + volumeId + "/action/setVolumeSize",
-                    String.format("{\"sizeInGB\":\"%s\"}", 
sizeInGB.toString()));
-            checkResponseOK(response);
+        // Volume capacity can only be increased. sizeInGB must be a positive 
number in granularity of 8 GB.
+        Boolean resizeVolumeStatus = post(
+                "/instances/Volume::" + volumeId + "/action/setVolumeSize",
+                String.format("{\"sizeInGB\":\"%s\"}", sizeInGB.toString()), 
Boolean.class);
+        if (resizeVolumeStatus != null && resizeVolumeStatus.booleanValue()) {
             return getVolume(volumeId);
-        } catch (final IOException e) {
-            LOG.error("Failed to resize PowerFlex volume due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
         }
         return null;
     }
@@ -426,33 +484,19 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
     public SnapshotGroup takeSnapshot(final Map<String, String> 
srcVolumeDestSnapshotMap) {
         Preconditions.checkArgument(srcVolumeDestSnapshotMap != null && 
!srcVolumeDestSnapshotMap.isEmpty(), "srcVolumeDestSnapshotMap cannot be null");
 
-        HttpResponse response = null;
-        try {
-            final List<SnapshotDef> defs = new ArrayList<>();
-            for (final String volumeId : srcVolumeDestSnapshotMap.keySet()) {
-                final SnapshotDef snapshotDef = new SnapshotDef();
-                snapshotDef.setVolumeId(volumeId);
-                String snapshotName = srcVolumeDestSnapshotMap.get(volumeId);
-                if (!Strings.isNullOrEmpty(snapshotName)) {
-                    
snapshotDef.setSnapshotName(srcVolumeDestSnapshotMap.get(volumeId));
-                }
-                defs.add(snapshotDef);
-            }
-            final SnapshotDefs snapshotDefs = new SnapshotDefs();
-            snapshotDefs.setSnapshotDefs(defs.toArray(new SnapshotDef[0]));
-            response = post("/instances/System/action/snapshotVolumes", 
snapshotDefs);
-            checkResponseOK(response);
-            ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
-            return mapper.readValue(response.getEntity().getContent(), 
SnapshotGroup.class);
-        } catch (final IOException e) {
-            LOG.error("Failed to take snapshot due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
+        final List<SnapshotDef> defs = new ArrayList<>();
+        for (final String volumeId : srcVolumeDestSnapshotMap.keySet()) {
+            final SnapshotDef snapshotDef = new SnapshotDef();
+            snapshotDef.setVolumeId(volumeId);
+            String snapshotName = srcVolumeDestSnapshotMap.get(volumeId);
+            if (!Strings.isNullOrEmpty(snapshotName)) {
+                
snapshotDef.setSnapshotName(srcVolumeDestSnapshotMap.get(volumeId));
             }
+            defs.add(snapshotDef);
         }
-        return null;
+        final SnapshotDefs snapshotDefs = new SnapshotDefs();
+        snapshotDefs.setSnapshotDefs(defs.toArray(new SnapshotDef[0]));
+        return post("/instances/System/action/snapshotVolumes", snapshotDefs, 
SnapshotGroup.class);
     }
 
     @Override
@@ -514,22 +558,12 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(systemId), "System 
id cannot be null");
         Preconditions.checkArgument(!Strings.isNullOrEmpty(snapshotGroupId), 
"Snapshot group id cannot be null");
 
-        HttpResponse response = null;
-        try {
-            response = post(
-                    "/instances/System::" + systemId + 
"/action/removeConsistencyGroupSnapshots",
-                    String.format("{\"snapGroupId\":\"%s\"}", 
snapshotGroupId));
-            checkResponseOK(response);
-            JsonNode node = new 
ObjectMapper().readTree(response.getEntity().getContent());
+        JsonNode node = post(
+                "/instances/System::" + systemId + 
"/action/removeConsistencyGroupSnapshots",
+                String.format("{\"snapGroupId\":\"%s\"}", snapshotGroupId), 
JsonNode.class);
+        if (node != null) {
             JsonNode noOfVolumesNode = node.get("numberOfVolumes");
             return noOfVolumesNode.asInt();
-        } catch (final IOException e) {
-            LOG.error("Failed to delete PowerFlex snapshot group due to: " + 
e.getMessage(), e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
         }
         return -1;
     }
@@ -539,31 +573,18 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume 
id cannot be null");
         
Preconditions.checkArgument(!Strings.isNullOrEmpty(snapshotVolumeName), 
"Snapshot name cannot be null");
 
-        HttpResponse response = null;
-        try {
-            final SnapshotDef[] snapshotDef = new SnapshotDef[1];
-            snapshotDef[0] = new SnapshotDef();
-            snapshotDef[0].setVolumeId(volumeId);
-            snapshotDef[0].setSnapshotName(snapshotVolumeName);
-            final SnapshotDefs snapshotDefs = new SnapshotDefs();
-            snapshotDefs.setSnapshotDefs(snapshotDef);
-
-            response = post("/instances/System/action/snapshotVolumes", 
snapshotDefs);
-            checkResponseOK(response);
-            ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
-            SnapshotGroup snapshotGroup = 
mapper.readValue(response.getEntity().getContent(), SnapshotGroup.class);
-            if (snapshotGroup != null) {
-                List<String> volumeIds = snapshotGroup.getVolumeIds();
-                if (volumeIds != null && !volumeIds.isEmpty()) {
-                    return getVolume(volumeIds.get(0));
-                }
-            }
-        } catch (final IOException e) {
-            LOG.error("Failed to take snapshot due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
+        final SnapshotDef[] snapshotDef = new SnapshotDef[1];
+        snapshotDef[0] = new SnapshotDef();
+        snapshotDef[0].setVolumeId(volumeId);
+        snapshotDef[0].setSnapshotName(snapshotVolumeName);
+        final SnapshotDefs snapshotDefs = new SnapshotDefs();
+        snapshotDefs.setSnapshotDefs(snapshotDef);
+
+        SnapshotGroup snapshotGroup = 
post("/instances/System/action/snapshotVolumes", snapshotDefs, 
SnapshotGroup.class);
+        if (snapshotGroup != null) {
+            List<String> volumeIds = snapshotGroup.getVolumeIds();
+            if (volumeIds != null && !volumeIds.isEmpty()) {
+                return getVolume(volumeIds.get(0));
             }
         }
         return null;
@@ -574,34 +595,25 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
         
Preconditions.checkArgument(!Strings.isNullOrEmpty(sourceSnapshotVolumeId), 
"Source snapshot volume id cannot be null");
         Preconditions.checkArgument(!Strings.isNullOrEmpty(destVolumeId), 
"Destination volume id cannot be null");
 
-        HttpResponse response = null;
-        try {
-            Volume sourceSnapshotVolume = getVolume(sourceSnapshotVolumeId);
-            if (sourceSnapshotVolume == null) {
-                throw new CloudRuntimeException("Source snapshot volume: " + 
sourceSnapshotVolumeId + " doesn't exists");
-            }
+        Volume sourceSnapshotVolume = getVolume(sourceSnapshotVolumeId);
+        if (sourceSnapshotVolume == null) {
+            throw new CloudRuntimeException("Source snapshot volume: " + 
sourceSnapshotVolumeId + " doesn't exists");
+        }
 
-            Volume destVolume = getVolume(destVolumeId);
-            if (sourceSnapshotVolume == null) {
-                throw new CloudRuntimeException("Destination volume: " + 
destVolumeId + " doesn't exists");
-            }
+        Volume destVolume = getVolume(destVolumeId);
+        if (sourceSnapshotVolume == null) {
+            throw new CloudRuntimeException("Destination volume: " + 
destVolumeId + " doesn't exists");
+        }
 
-            if 
(!sourceSnapshotVolume.getVtreeId().equals(destVolume.getVtreeId())) {
-                throw new CloudRuntimeException("Unable to revert, source 
snapshot volume and destination volume doesn't belong to same volume tree");
-            }
+        if 
(!sourceSnapshotVolume.getVtreeId().equals(destVolume.getVtreeId())) {
+            throw new CloudRuntimeException("Unable to revert, source snapshot 
volume and destination volume doesn't belong to same volume tree");
+        }
 
-            response = post(
-                    "/instances/Volume::" + destVolumeId + 
"/action/overwriteVolumeContent",
-                    
String.format("{\"srcVolumeId\":\"%s\",\"allowOnExtManagedVol\":\"TRUE\"}", 
sourceSnapshotVolumeId));
-            checkResponseOK(response);
-            return true;
-        } catch (final IOException e) {
-            LOG.error("Failed to map PowerFlex volume due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
+        Boolean overwriteVolumeContentStatus = post(
+                "/instances/Volume::" + destVolumeId + 
"/action/overwriteVolumeContent",
+                
String.format("{\"srcVolumeId\":\"%s\",\"allowOnExtManagedVol\":\"TRUE\"}", 
sourceSnapshotVolumeId), Boolean.class);
+        if (overwriteVolumeContentStatus != null) {
+            return overwriteVolumeContentStatus;
         }
         return false;
     }
@@ -611,24 +623,15 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume 
id cannot be null");
         Preconditions.checkArgument(!Strings.isNullOrEmpty(sdcId), "Sdc Id 
cannot be null");
 
-        HttpResponse response = null;
-        try {
-            if (isVolumeMappedToSdc(volumeId, sdcId)) {
-                return true;
-            }
-
-            response = post(
-                    "/instances/Volume::" + volumeId + "/action/addMappedSdc",
-                    
String.format("{\"sdcId\":\"%s\",\"allowMultipleMappings\":\"TRUE\"}", sdcId));
-            checkResponseOK(response);
+        if (isVolumeMappedToSdc(volumeId, sdcId)) {
             return true;
-        } catch (final IOException e) {
-            LOG.error("Failed to map PowerFlex volume due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
+        }
+
+        Boolean mapVolumeToSdcStatus = post(
+                "/instances/Volume::" + volumeId + "/action/addMappedSdc",
+                
String.format("{\"sdcId\":\"%s\",\"allowMultipleMappings\":\"TRUE\"}", sdcId), 
Boolean.class);
+        if (mapVolumeToSdcStatus != null) {
+            return mapVolumeToSdcStatus;
         }
         return false;
     }
@@ -642,31 +645,22 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
         Preconditions.checkArgument(bandwidthLimitInKbps != null && 
(bandwidthLimitInKbps == 0 || (bandwidthLimitInKbps > 0 && bandwidthLimitInKbps 
% 1024 == 0)),
                 "Bandwidth limit(Kbps) must be 0 (unlimited) or in granularity 
of 1024");
 
-        HttpResponse response = null;
-        try {
-            if (mapVolumeToSdc(volumeId, sdcId)) {
-                long iopsLimitVal = 0;
-                if (iopsLimit != null && iopsLimit.longValue() > 0) {
-                    iopsLimitVal = iopsLimit.longValue();
-                }
-
-                long bandwidthLimitInKbpsVal = 0;
-                if (bandwidthLimitInKbps != null && 
bandwidthLimitInKbps.longValue() > 0) {
-                    bandwidthLimitInKbpsVal = bandwidthLimitInKbps.longValue();
-                }
+        if (mapVolumeToSdc(volumeId, sdcId)) {
+            long iopsLimitVal = 0;
+            if (iopsLimit != null && iopsLimit.longValue() > 0) {
+                iopsLimitVal = iopsLimit.longValue();
+            }
 
-                response = post(
-                        "/instances/Volume::" + volumeId + 
"/action/setMappedSdcLimits",
-                        
String.format("{\"sdcId\":\"%s\",\"bandwidthLimitInKbps\":\"%d\",\"iopsLimit\":\"%d\"}",
 sdcId, bandwidthLimitInKbpsVal, iopsLimitVal));
-                checkResponseOK(response);
-                return true;
+            long bandwidthLimitInKbpsVal = 0;
+            if (bandwidthLimitInKbps != null && 
bandwidthLimitInKbps.longValue() > 0) {
+                bandwidthLimitInKbpsVal = bandwidthLimitInKbps.longValue();
             }
-        } catch (final IOException e) {
-            LOG.error("Failed to map PowerFlex volume with limits due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
+
+            Boolean setVolumeSdcLimitsStatus = post(
+                    "/instances/Volume::" + volumeId + 
"/action/setMappedSdcLimits",
+                    
String.format("{\"sdcId\":\"%s\",\"bandwidthLimitInKbps\":\"%d\",\"iopsLimit\":\"%d\"}",
 sdcId, bandwidthLimitInKbpsVal, iopsLimitVal), Boolean.class);
+            if (setVolumeSdcLimitsStatus != null) {
+                return setVolumeSdcLimitsStatus;
             }
         }
         return false;
@@ -677,21 +671,12 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume 
id cannot be null");
         Preconditions.checkArgument(!Strings.isNullOrEmpty(sdcId), "Sdc Id 
cannot be null");
 
-        HttpResponse response = null;
-        try {
-            if (isVolumeMappedToSdc(volumeId, sdcId)) {
-                response = post(
-                        "/instances/Volume::" + volumeId + 
"/action/removeMappedSdc",
-                        
String.format("{\"sdcId\":\"%s\",\"skipApplianceValidation\":\"TRUE\"}", 
sdcId));
-                checkResponseOK(response);
-                return true;
-            }
-        } catch (final IOException e) {
-            LOG.error("Failed to unmap PowerFlex volume due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
+        if (isVolumeMappedToSdc(volumeId, sdcId)) {
+            Boolean unmapVolumeFromSdcStatus = post(
+                    "/instances/Volume::" + volumeId + 
"/action/removeMappedSdc",
+                    
String.format("{\"sdcId\":\"%s\",\"skipApplianceValidation\":\"TRUE\"}", 
sdcId), Boolean.class);
+            if (unmapVolumeFromSdcStatus != null) {
+                return unmapVolumeFromSdcStatus;
             }
         }
         return false;
@@ -701,30 +686,21 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
     public boolean unmapVolumeFromAllSdcs(final String volumeId) {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume 
id cannot be null");
 
-        HttpResponse response = null;
-        try {
-            Volume volume = getVolume(volumeId);
-            if (volume == null) {
-                return false;
-            }
-
-            List<SdcMappingInfo> mappedSdcList = volume.getMappedSdcList();
-            if (mappedSdcList == null || mappedSdcList.isEmpty()) {
-                return true;
-            }
+        Volume volume = getVolume(volumeId);
+        if (volume == null) {
+            return false;
+        }
 
-            response = post(
-                    "/instances/Volume::" + volumeId + 
"/action/removeMappedSdc",
-                    "{\"allSdcs\": \"\"}");
-            checkResponseOK(response);
+        List<SdcMappingInfo> mappedSdcList = volume.getMappedSdcList();
+        if (mappedSdcList == null || mappedSdcList.isEmpty()) {
             return true;
-        } catch (final IOException e) {
-            LOG.error("Failed to unmap PowerFlex volume from all SDCs due 
to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
+        }
+
+        Boolean unmapVolumeFromAllSdcsStatus = post(
+                "/instances/Volume::" + volumeId + "/action/removeMappedSdc",
+                "{\"allSdcs\": \"\"}", Boolean.class);
+        if (unmapVolumeFromAllSdcsStatus != null) {
+            return unmapVolumeFromAllSdcsStatus;
         }
         return false;
     }
@@ -759,23 +735,14 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
     public boolean deleteVolume(final String volumeId) {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume 
id cannot be null");
 
-        HttpResponse response = null;
         try {
-            try {
-                unmapVolumeFromAllSdcs(volumeId);
-            } catch (Exception ignored) {}
-            response = post(
-                    "/instances/Volume::" + volumeId + "/action/removeVolume",
-                    "{\"removeMode\":\"ONLY_ME\"}");
-            checkResponseOK(response);
-            return true;
-        } catch (final IOException e) {
-            LOG.error("Failed to delete PowerFlex volume due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
+            unmapVolumeFromAllSdcs(volumeId);
+        } catch (Exception ignored) {}
+        Boolean removeVolumeStatus = post(
+                "/instances/Volume::" + volumeId + "/action/removeVolume",
+                "{\"removeMode\":\"ONLY_ME\"}", Boolean.class);
+        if (removeVolumeStatus != null) {
+            return removeVolumeStatus;
         }
         return false;
     }
@@ -797,21 +764,8 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
             LOG.debug("Migrating the volume: " + srcVolumeId + " on the src 
pool: " + srcPoolId + " to the dest pool: " + destPoolId +
                     " in the same PowerFlex cluster");
 
-            HttpResponse response = null;
-            try {
-                response = post(
-                        "/instances/Volume::" + srcVolumeId + 
"/action/migrateVTree",
-                        String.format("{\"destSPId\":\"%s\"}", destPoolId));
-                checkResponseOK(response);
-            } catch (final IOException e) {
-                LOG.error("Unable to migrate PowerFlex volume due to: ", e);
-                checkResponseTimeOut(e);
-                throw e;
-            } finally {
-                if (response != null) {
-                    EntityUtils.consumeQuietly(response.getEntity());
-                }
-            }
+            post("/instances/Volume::" + srcVolumeId + "/action/migrateVTree",
+                    String.format("{\"destSPId\":\"%s\"}", destPoolId), 
Boolean.class);
 
             LOG.debug("Wait until the migration is complete for the volume: " 
+ srcVolumeId);
             long migrationStartTime = System.currentTimeMillis();
@@ -899,22 +853,9 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
             return null;
         }
 
-        HttpResponse response = null;
-        try {
-            response = get("/instances/VTree::" + volumeTreeId);
-            checkResponseOK(response);
-            ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
-            VTree volumeTree = 
mapper.readValue(response.getEntity().getContent(), VTree.class);
-            if (volumeTree != null && volumeTree.getVTreeMigrationInfo() != 
null) {
-                return volumeTree.getVTreeMigrationInfo().getMigrationStatus();
-            }
-        } catch (final IOException e) {
-            LOG.error("Failed to migrate PowerFlex volume due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
+        VTree volumeTree = get("/instances/VTree::" + volumeTreeId, 
VTree.class);
+        if (volumeTree != null && volumeTree.getVTreeMigrationInfo() != null) {
+            return volumeTree.getVTreeMigrationInfo().getMigrationStatus();
         }
         return null;
     }
@@ -922,53 +863,49 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
     private boolean rollbackVolumeMigration(final String srcVolumeId) {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(srcVolumeId), "src 
volume id cannot be null");
 
-        HttpResponse response = null;
-        try {
-            Volume volume = getVolume(srcVolumeId);
-            VTreeMigrationInfo.MigrationStatus migrationStatus = 
getVolumeTreeMigrationStatus(volume.getVtreeId());
-            if (migrationStatus != null && migrationStatus == 
VTreeMigrationInfo.MigrationStatus.NotInMigration) {
-                LOG.debug("Volume: " + srcVolumeId + " is not migrating, no 
need to rollback");
-                return true;
-            }
+        Volume volume = getVolume(srcVolumeId);
+        if (volume == null) {
+            LOG.warn("Unable to rollback volume migration, couldn't get 
details for the volume: " + srcVolumeId);
+            return false;
+        }
 
-            pauseVolumeMigration(srcVolumeId, true); // Pause forcefully
-            // Wait few secs for volume migration to change to Paused state
-            boolean paused = false;
-            int retryCount = 3;
-            while (retryCount > 0) {
-                try {
-                    Thread.sleep(3000); // Try after few secs
-                    migrationStatus = 
getVolumeTreeMigrationStatus(volume.getVtreeId()); // Get updated migration 
status
-                    if (migrationStatus != null && migrationStatus == 
VTreeMigrationInfo.MigrationStatus.Paused) {
-                        LOG.debug("Migration for the volume: " + srcVolumeId + 
" paused");
-                        paused = true;
-                        break;
-                    }
-                } catch (Exception ex) {
-                    LOG.warn("Exception while checking for migration pause 
status of the volume: " + srcVolumeId + " - " + ex.getLocalizedMessage());
-                    // don't do anything
-                } finally {
-                    retryCount--;
+        VTreeMigrationInfo.MigrationStatus migrationStatus = 
getVolumeTreeMigrationStatus(volume.getVtreeId());
+        if (migrationStatus != null && migrationStatus == 
VTreeMigrationInfo.MigrationStatus.NotInMigration) {
+            LOG.debug("Volume: " + srcVolumeId + " is not migrating, no need 
to rollback");
+            return true;
+        }
+
+        pauseVolumeMigration(srcVolumeId, true); // Pause forcefully
+        // Wait few secs for volume migration to change to Paused state
+        boolean paused = false;
+        int retryCount = 3;
+        while (retryCount > 0) {
+            try {
+                Thread.sleep(3000); // Try after few secs
+                migrationStatus = 
getVolumeTreeMigrationStatus(volume.getVtreeId()); // Get updated migration 
status
+                if (migrationStatus != null && migrationStatus == 
VTreeMigrationInfo.MigrationStatus.Paused) {
+                    LOG.debug("Migration for the volume: " + srcVolumeId + " 
paused");
+                    paused = true;
+                    break;
                 }
+            } catch (Exception ex) {
+                LOG.warn("Exception while checking for migration pause status 
of the volume: " + srcVolumeId + " - " + ex.getLocalizedMessage());
+                // don't do anything
+            } finally {
+                retryCount--;
             }
+        }
 
-            if (paused) {
-                // Rollback migration to the src pool (should be quick)
-                response = post(
-                        "/instances/Volume::" + srcVolumeId + 
"/action/migrateVTree",
-                        String.format("{\"destSPId\":\"%s\"}", 
volume.getStoragePoolId()));
-                checkResponseOK(response);
-                return true;
-            } else {
-                LOG.warn("Migration for the volume: " + srcVolumeId + " didn't 
pause, couldn't rollback");
-            }
-        } catch (final IOException e) {
-            LOG.error("Failed to rollback volume migration due to: ", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
+        if (paused) {
+            // Rollback migration to the src pool (should be quick)
+            Boolean migrateVTreeStatus = post(
+                    "/instances/Volume::" + srcVolumeId + 
"/action/migrateVTree",
+                    String.format("{\"destSPId\":\"%s\"}", 
volume.getStoragePoolId()), Boolean.class);
+            if (migrateVTreeStatus != null) {
+                return migrateVTreeStatus;
             }
+        } else {
+            LOG.warn("Migration for the volume: " + srcVolumeId + " didn't 
pause, couldn't rollback");
         }
         return false;
     }
@@ -979,23 +916,14 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
             return false;
         }
 
-        HttpResponse response = null;
-        try {
-            // When paused gracefully, all data currently being moved is 
allowed to complete the migration.
-            // When paused forcefully, migration of unfinished data is aborted 
and data is left at the source, if possible.
-            // Pausing forcefully carries a potential risk to data.
-            response = post(
-                    "/instances/Volume::" + volumeId + 
"/action/pauseVTreeMigration",
-                    String.format("{\"pauseType\":\"%s\"}", forced ? 
"Forcefully" : "Gracefully"));
-            checkResponseOK(response);
-            return true;
-        } catch (final IOException e) {
-            LOG.error("Failed to pause migration of the volume due to: ", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
+        // When paused gracefully, all data currently being moved is allowed 
to complete the migration.
+        // When paused forcefully, migration of unfinished data is aborted and 
data is left at the source, if possible.
+        // Pausing forcefully carries a potential risk to data.
+        Boolean pauseVTreeMigrationStatus = post(
+                "/instances/Volume::" + volumeId + 
"/action/pauseVTreeMigration",
+                String.format("{\"pauseType\":\"%s\"}", forced ? "Forcefully" 
: "Gracefully"), Boolean.class);
+        if (pauseVTreeMigrationStatus != null) {
+            return pauseVTreeMigrationStatus;
         }
         return false;
     }
@@ -1006,20 +934,9 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
 
     @Override
     public List<StoragePool> listStoragePools() {
-        HttpResponse response = null;
-        try {
-            response = get("/types/StoragePool/instances");
-            checkResponseOK(response);
-            ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
-            StoragePool[] pools = 
mapper.readValue(response.getEntity().getContent(), StoragePool[].class);
+        StoragePool[] pools = get("/types/StoragePool/instances", 
StoragePool[].class);
+        if (pools != null) {
             return Arrays.asList(pools);
-        } catch (final IOException e) {
-            LOG.error("Failed to list PowerFlex storage pools due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
         }
         return new ArrayList<>();
     }
@@ -1027,72 +944,29 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
     @Override
     public StoragePool getStoragePool(String poolId) {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(poolId), "Storage 
pool id cannot be null");
-
-        HttpResponse response = null;
-        try {
-            response = get("/instances/StoragePool::" + poolId);
-            checkResponseOK(response);
-            ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
-            return mapper.readValue(response.getEntity().getContent(), 
StoragePool.class);
-        } catch (final IOException e) {
-            LOG.error("Failed to get storage pool due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
-        }
-        return null;
+        return get("/instances/StoragePool::" + poolId, StoragePool.class);
     }
 
     @Override
     public StoragePoolStatistics getStoragePoolStatistics(String poolId) {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(poolId), "Storage 
pool id cannot be null");
-
-        HttpResponse response = null;
-        try {
-            response = get("/instances/StoragePool::" + poolId + 
"/relationships/Statistics");
-            checkResponseOK(response);
-            ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
-            return mapper.readValue(response.getEntity().getContent(), 
StoragePoolStatistics.class);
-        } catch (final IOException e) {
-            LOG.error("Failed to get storage pool due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
-        }
-        return null;
+        return get("/instances/StoragePool::" + poolId + 
"/relationships/Statistics", StoragePoolStatistics.class);
     }
 
     @Override
     public VolumeStatistics getVolumeStatistics(String volumeId) {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(volumeId), "Volume 
id cannot be null");
 
-        HttpResponse response = null;
-        try {
-            Volume volume = getVolume(volumeId);
-            if (volume != null) {
-                String volumeTreeId = volume.getVtreeId();
-                if (!Strings.isNullOrEmpty(volumeTreeId)) {
-                    response = get("/instances/VTree::" + volumeTreeId + 
"/relationships/Statistics");
-                    checkResponseOK(response);
-                    ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
-                    VolumeStatistics volumeStatistics = 
mapper.readValue(response.getEntity().getContent(), VolumeStatistics.class);
-                    if (volumeStatistics != null) {
-                        
volumeStatistics.setAllocatedSizeInKb(volume.getSizeInKb());
-                        return volumeStatistics;
-                    }
+        Volume volume = getVolume(volumeId);
+        if (volume != null) {
+            String volumeTreeId = volume.getVtreeId();
+            if (!Strings.isNullOrEmpty(volumeTreeId)) {
+                VolumeStatistics volumeStatistics = get("/instances/VTree::" + 
volumeTreeId + "/relationships/Statistics", VolumeStatistics.class);
+                if (volumeStatistics != null) {
+                    
volumeStatistics.setAllocatedSizeInKb(volume.getSizeInKb());
+                    return volumeStatistics;
                 }
             }
-        } catch (final IOException e) {
-            LOG.error("Failed to get volume stats due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
         }
 
         return null;
@@ -1102,22 +976,9 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
     public String getSystemId(String protectionDomainId) {
         
Preconditions.checkArgument(!Strings.isNullOrEmpty(protectionDomainId), 
"Protection domain id cannot be null");
 
-        HttpResponse response = null;
-        try {
-            response = get("/instances/ProtectionDomain::" + 
protectionDomainId);
-            checkResponseOK(response);
-            ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
-            ProtectionDomain protectionDomain = 
mapper.readValue(response.getEntity().getContent(), ProtectionDomain.class);
-            if (protectionDomain != null) {
-                return protectionDomain.getSystemId();
-            }
-        } catch (final IOException e) {
-            LOG.error("Failed to get protection domain details due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
+        ProtectionDomain protectionDomain = 
get("/instances/ProtectionDomain::" + protectionDomainId, 
ProtectionDomain.class);
+        if (protectionDomain != null) {
+            return protectionDomain.getSystemId();
         }
         return null;
     }
@@ -1126,20 +987,9 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
     public List<Volume> listVolumesInStoragePool(String poolId) {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(poolId), "Storage 
pool id cannot be null");
 
-        HttpResponse response = null;
-        try {
-            response = get("/instances/StoragePool::" + poolId + 
"/relationships/Volume");
-            checkResponseOK(response);
-            ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
-            Volume[] volumes = 
mapper.readValue(response.getEntity().getContent(), Volume[].class);
+        Volume[] volumes = get("/instances/StoragePool::" + poolId + 
"/relationships/Volume", Volume[].class);
+        if (volumes != null) {
             return Arrays.asList(volumes);
-        } catch (final IOException e) {
-            LOG.error("Failed to list volumes in storage pool due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
         }
         return new ArrayList<>();
     }
@@ -1150,20 +1000,9 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
 
     @Override
     public List<Sdc> listSdcs() {
-        HttpResponse response = null;
-        try {
-            response = get("/types/Sdc/instances");
-            checkResponseOK(response);
-            ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
-            Sdc[] sdcs = mapper.readValue(response.getEntity().getContent(), 
Sdc[].class);
+        Sdc[] sdcs = get("/types/Sdc/instances", Sdc[].class);
+        if (sdcs != null) {
             return Arrays.asList(sdcs);
-        } catch (final IOException e) {
-            LOG.error("Failed to list SDCs due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
         }
         return new ArrayList<>();
     }
@@ -1171,43 +1010,16 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
     @Override
     public Sdc getSdc(String sdcId) {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(sdcId), "Sdc id 
cannot be null");
-
-        HttpResponse response = null;
-        try {
-            response = get("/instances/Sdc::" + sdcId);
-            checkResponseOK(response);
-            ObjectMapper mapper = new 
ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 
false);
-            return mapper.readValue(response.getEntity().getContent(), 
Sdc.class);
-        } catch (final IOException e) {
-            LOG.error("Failed to get volume due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
-        }
-        return null;
+        return get("/instances/Sdc::" + sdcId, Sdc.class);
     }
 
     @Override
     public Sdc getSdcByIp(String ipAddress) {
         Preconditions.checkArgument(!Strings.isNullOrEmpty(ipAddress), "IP 
address cannot be null");
 
-        HttpResponse response = null;
-        try {
-            response = post("/types/Sdc/instances/action/queryIdByKey", 
String.format("{\"ip\":\"%s\"}", ipAddress));
-            checkResponseOK(response);
-            String sdcId = EntityUtils.toString(response.getEntity());
-            if (!Strings.isNullOrEmpty(sdcId)) {
-                return getSdc(sdcId.replace("\"", ""));
-            }
-        } catch (final IOException e) {
-            LOG.error("Failed to get volume due to:", e);
-            checkResponseTimeOut(e);
-        } finally {
-            if (response != null) {
-                EntityUtils.consumeQuietly(response.getEntity());
-            }
+        String sdcId = post("/types/Sdc/instances/action/queryIdByKey", 
String.format("{\"ip\":\"%s\"}", ipAddress), String.class);
+        if (!Strings.isNullOrEmpty(sdcId)) {
+            return getSdc(sdcId.replace("\"", ""));
         }
         return null;
     }
@@ -1252,4 +1064,27 @@ public class ScaleIOGatewayClientImpl implements 
ScaleIOGatewayClient {
 
         return false;
     }
+
+    private String getConnectionManagerStats() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("\n").append("Client Connection Manager Stats => ");
+        if (connectionManager != null) {
+            sb.append("MaxTotal: 
").append(connectionManager.getMaxTotal()).append(", ");
+            sb.append("DefaultMaxPerRoute: 
").append(connectionManager.getDefaultMaxPerRoute());
+
+            PoolStats poolStats = connectionManager.getTotalStats();
+            if (poolStats != null) {
+                sb.append(", ");
+                sb.append("Available: 
").append(poolStats.getAvailable()).append(", ");
+                sb.append("Leased: ").append(poolStats.getLeased()).append(", 
");
+                sb.append("Max: ").append(poolStats.getMax()).append(", ");
+                sb.append("Pending: ").append(poolStats.getPending());
+            }
+        } else {
+            sb.append("NULL");
+        }
+
+        sb.append("\n");
+        return sb.toString();
+    }
 }
diff --git 
a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycle.java
 
b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycle.java
index 5c9ddea..edebdac 100644
--- 
a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycle.java
+++ 
b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycle.java
@@ -106,7 +106,8 @@ public class ScaleIOPrimaryDataStoreLifeCycle implements 
PrimaryDataStoreLifeCyc
     private org.apache.cloudstack.storage.datastore.api.StoragePool 
findStoragePool(String url, String username, String password, String 
storagePoolName) {
         try {
             final int clientTimeout = 
StorageManager.STORAGE_POOL_CLIENT_TIMEOUT.value();
-            ScaleIOGatewayClient client = ScaleIOGatewayClient.getClient(url, 
username, password, false, clientTimeout);
+            final int clientMaxConnections = 
StorageManager.STORAGE_POOL_CLIENT_MAX_CONNECTIONS.value();
+            ScaleIOGatewayClient client = ScaleIOGatewayClient.getClient(url, 
username, password, false, clientTimeout, clientMaxConnections);
             List<org.apache.cloudstack.storage.datastore.api.StoragePool> 
storagePools = client.listStoragePools();
             for (org.apache.cloudstack.storage.datastore.api.StoragePool pool 
: storagePools) {
                 if (pool.getName().equals(storagePoolName)) {
@@ -121,9 +122,9 @@ public class ScaleIOPrimaryDataStoreLifeCycle implements 
PrimaryDataStoreLifeCyc
             }
         } catch (NoSuchAlgorithmException | KeyManagementException | 
URISyntaxException e) {
             LOGGER.error("Failed to add storage pool", e);
-            throw new CloudRuntimeException("Failed to establish connection 
with PowerFlex Gateway to validate storage pool");
+            throw new CloudRuntimeException("Failed to establish connection 
with PowerFlex Gateway to find and validate storage pool: " + storagePoolName);
         }
-        throw new CloudRuntimeException("Failed to find the provided storage 
pool name in discovered PowerFlex storage pools");
+        throw new CloudRuntimeException("Failed to find the provided storage 
pool name: " + storagePoolName + " in the discovered PowerFlex storage pools");
     }
 
     @SuppressWarnings("unchecked")
diff --git 
a/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImplTest.java
 
b/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImplTest.java
index 1082310..80a78c8 100644
--- 
a/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImplTest.java
+++ 
b/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/client/ScaleIOGatewayClientImplTest.java
@@ -19,30 +19,179 @@
 
 package org.apache.cloudstack.storage.datastore.client;
 
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.containing;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.ok;
+import static com.github.tomakehurst.wiremock.client.WireMock.post;
+import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.unauthorized;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static 
com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
+
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.storage.datastore.api.Volume;
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import com.cloud.storage.Storage;
 import com.cloud.utils.exception.CloudRuntimeException;
+import com.github.tomakehurst.wiremock.client.BasicCredentials;
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
 
 @RunWith(MockitoJUnitRunner.class)
 public class ScaleIOGatewayClientImplTest {
+    private final int port = 443;
+    private final int timeout = 30;
+    private final int maxConnections = 50;
+    private final String username = "admin";
+    private final String password = "P@ssword123";
+    private final String sessionKey = 
"YWRtaW46MTYyMzM0OTc4NDk0MTo2MWQ2NGQzZWJhMTVmYTVkNDIwNjZmOWMwZDg0ZGZmOQ";
+    private ScaleIOGatewayClient client = null;
 
-    ScaleIOGatewayClientImpl client;
+    @Rule
+    public WireMockRule wireMockRule = new WireMockRule(wireMockConfig()
+            .httpsPort(port)
+            .needClientAuth(false)
+            .basicAdminAuthenticator(username, password)
+            .bindAddress("localhost"));
 
     @Before
     public void setUp() throws Exception {
+        wireMockRule.stubFor(get("/api/login")
+                .willReturn(ok()
+                        .withHeader("Content-Type", 
"application/json;charset=UTF-8")
+                        .withBody(sessionKey)));
+
+        client = new ScaleIOGatewayClientImpl("https://localhost/api";, 
username, password, false, timeout, maxConnections);
+
+        wireMockRule.stubFor(post("/api/types/Volume/instances")
+                .willReturn(aResponse()
+                        .withHeader("Content-Type", 
"application/json;charset=UTF-8")
+                        .withStatus(200)
+                        .withBody("{\"id\":\"c948d0b10000000a\"}")));
+
+        wireMockRule.stubFor(get("/api/instances/Volume::c948d0b10000000a")
+                .willReturn(aResponse()
+                        .withHeader("Content-Type", 
"application/json;charset=UTF-8")
+                        .withStatus(200)
+                        
.withBody("{\"storagePoolId\":\"4daaa55e00000000\",\"dataLayout\":\"MediumGranularity\",\"vtreeId\":\"657e289500000009\","
+                                + 
"\"sizeInKb\":8388608,\"snplIdOfAutoSnapshot\":null,\"volumeType\":\"ThinProvisioned\",\"consistencyGroupId\":null,"
+                                + 
"\"ancestorVolumeId\":null,\"notGenuineSnapshot\":false,\"accessModeLimit\":\"ReadWrite\",\"secureSnapshotExpTime\":0,"
+                                + 
"\"useRmcache\":false,\"managedBy\":\"ScaleIO\",\"lockedAutoSnapshot\":false,\"lockedAutoSnapshotMarkedForRemoval\":false,"
+                                + 
"\"autoSnapshotGroupId\":null,\"compressionMethod\":\"Invalid\",\"pairIds\":null,\"timeStampIsAccurate\":false,\"mappedSdcInfo\":null,"
+                                + 
"\"retentionLevels\":[],\"snplIdOfSourceVolume\":null,\"volumeReplicationState\":\"UnmarkedForReplication\",\"replicationJournalVolume\":false,"
+                                + 
"\"replicationTimeStamp\":0,\"originalExpiryTime\":0,\"creationTime\":1623335880,\"name\":\"testvolume\",\"id\":\"c948d0b10000000a\"}")));
     }
 
     @After
     public void tearDown() throws Exception {
     }
 
+    @Test
+    public void testClientAuthSuccess() {
+        Assert.assertNotNull(client);
+        wireMockRule.verify(getRequestedFor(urlEqualTo("/api/login"))
+                .withBasicAuth(new BasicCredentials(username, password)));
+
+        wireMockRule.stubFor(get("/api/types/StoragePool/instances")
+                .willReturn(aResponse()
+                        .withHeader("Content-Type", 
"application/json;charset=UTF-8")
+                        .withStatus(200)
+                        .withBody("")));
+
+        client.listStoragePools();
+
+        
wireMockRule.verify(getRequestedFor(urlEqualTo("/api/types/StoragePool/instances"))
+                .withBasicAuth(new BasicCredentials(username, sessionKey)));
+    }
+
     @Test(expected = CloudRuntimeException.class)
-    public void testClient() throws Exception {
-        client = (ScaleIOGatewayClientImpl) 
ScaleIOGatewayClient.getClient("https://10.2.3.149/api";,
-                "admin", "P@ssword123", false, 60);
+    public void testClientAuthFailure() throws Exception {
+        wireMockRule.stubFor(get("/api/login")
+                .willReturn(unauthorized()
+                        .withHeader("Content-Type", 
"application/json;charset=UTF-8")
+                        .withBody("")));
+
+        new ScaleIOGatewayClientImpl("https://localhost/api";, username, 
password, false, timeout, maxConnections);
+    }
+
+    @Test(expected = ServerApiException.class)
+    public void testRequestTimeout() {
+        Assert.assertNotNull(client);
+        wireMockRule.verify(getRequestedFor(urlEqualTo("/api/login"))
+                .withBasicAuth(new BasicCredentials(username, password)));
+
+        wireMockRule.stubFor(get("/api/types/StoragePool/instances")
+                .willReturn(aResponse()
+                        .withHeader("Content-Type", 
"application/json;charset=UTF-8")
+                        .withStatus(200)
+                        .withFixedDelay(2 * timeout * 1000)
+                        .withBody("")));
+
+        client.listStoragePools();
+    }
+
+    @Test
+    public void testCreateSingleVolume() {
+        Assert.assertNotNull(client);
+        wireMockRule.verify(getRequestedFor(urlEqualTo("/api/login"))
+                .withBasicAuth(new BasicCredentials(username, password)));
+
+        final String volumeName = "testvolume";
+        final String scaleIOStoragePoolId = "4daaa55e00000000";
+        final int sizeInGb = 8;
+        Volume scaleIOVolume = client.createVolume(volumeName, 
scaleIOStoragePoolId, sizeInGb, Storage.ProvisioningType.THIN);
+
+        
wireMockRule.verify(postRequestedFor(urlEqualTo("/api/types/Volume/instances"))
+                .withBasicAuth(new BasicCredentials(username, sessionKey))
+                .withRequestBody(containing("\"name\":\"" + volumeName + "\""))
+                .withHeader("Content-Type", equalTo("application/json")));
+        
wireMockRule.verify(getRequestedFor(urlEqualTo("/api/instances/Volume::c948d0b10000000a"))
+                .withBasicAuth(new BasicCredentials(username, sessionKey)));
+
+        Assert.assertNotNull(scaleIOVolume);
+        Assert.assertEquals(scaleIOVolume.getId(), "c948d0b10000000a");
+        Assert.assertEquals(scaleIOVolume.getName(), volumeName);
+        Assert.assertEquals(scaleIOVolume.getStoragePoolId(), 
scaleIOStoragePoolId);
+        Assert.assertEquals(scaleIOVolume.getSizeInKb(), Long.valueOf(sizeInGb 
* 1024 * 1024));
+        Assert.assertEquals(scaleIOVolume.getVolumeType(), 
Volume.VolumeType.ThinProvisioned);
+    }
+
+    @Test
+    public void testCreateMultipleVolumes() {
+        Assert.assertNotNull(client);
+        wireMockRule.verify(getRequestedFor(urlEqualTo("/api/login"))
+                .withBasicAuth(new BasicCredentials(username, password)));
+
+        final String volumeNamePrefix = "testvolume_";
+        final String scaleIOStoragePoolId = "4daaa55e00000000";
+        final int sizeInGb = 8;
+        final int volumesCount = 1000;
+
+        for (int i = 1; i <= volumesCount; i++) {
+            String volumeName = volumeNamePrefix + i;
+            Volume scaleIOVolume = client.createVolume(volumeName, 
scaleIOStoragePoolId, sizeInGb, Storage.ProvisioningType.THIN);
+
+            Assert.assertNotNull(scaleIOVolume);
+            Assert.assertEquals(scaleIOVolume.getId(), "c948d0b10000000a");
+            Assert.assertEquals(scaleIOVolume.getStoragePoolId(), 
scaleIOStoragePoolId);
+            Assert.assertEquals(scaleIOVolume.getSizeInKb(), 
Long.valueOf(sizeInGb * 1024 * 1024));
+            Assert.assertEquals(scaleIOVolume.getVolumeType(), 
Volume.VolumeType.ThinProvisioned);
+        }
+
+        wireMockRule.verify(volumesCount, 
postRequestedFor(urlEqualTo("/api/types/Volume/instances"))
+                .withBasicAuth(new BasicCredentials(username, sessionKey))
+                .withRequestBody(containing("\"name\":\"" + volumeNamePrefix))
+                .withHeader("Content-Type", equalTo("application/json")));
+        wireMockRule.verify(volumesCount, 
getRequestedFor(urlEqualTo("/api/instances/Volume::c948d0b10000000a"))
+                .withBasicAuth(new BasicCredentials(username, sessionKey)));
     }
 }
\ No newline at end of file
diff --git 
a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java 
b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
index cb7e4b5..f431945 100755
--- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -474,6 +474,9 @@ public class ConfigurationManagerImpl extends ManagerBase 
implements Configurati
         configValuesForValidation.add("externaldhcp.vmip.max.retry");
         configValuesForValidation.add("externaldhcp.vmipFetch.threadPool.max");
         configValuesForValidation.add("remote.access.vpn.psk.length");
+        
configValuesForValidation.add(StorageManager.STORAGE_POOL_DISK_WAIT.key());
+        
configValuesForValidation.add(StorageManager.STORAGE_POOL_CLIENT_TIMEOUT.key());
+        
configValuesForValidation.add(StorageManager.STORAGE_POOL_CLIENT_MAX_CONNECTIONS.key());
     }
 
     private void weightBasedParametersForValidation() {
diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java 
b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
index 5e7be30..9e6cb3f 100644
--- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
@@ -3130,6 +3130,7 @@ public class StorageManagerImpl extends ManagerBase 
implements StorageManager, C
                 MaxNumberOfManagedClusteredFileSystems,
                 STORAGE_POOL_DISK_WAIT,
                 STORAGE_POOL_CLIENT_TIMEOUT,
+                STORAGE_POOL_CLIENT_MAX_CONNECTIONS,
                 PRIMARY_STORAGE_DOWNLOAD_WAIT,
                 SecStorageMaxMigrateSessions,
                 MaxDataMigrationWaitTime
diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java 
b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
index a2b2a49..bdad40f 100644
--- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
@@ -1485,6 +1485,13 @@ public class VolumeApiServiceImpl extends ManagerBase 
implements VolumeApiServic
         }
     }
 
+    private void removeVolume(long volumeId) {
+        final VolumeVO volume = _volsDao.findById(volumeId);
+        if (volume != null) {
+            _volsDao.remove(volumeId);
+        }
+    }
+
     protected boolean stateTransitTo(Volume vol, Volume.Event event) throws 
NoTransitionException {
         return _volStateMachine.transitTo(vol, event, null, _volsDao);
     }
@@ -1526,6 +1533,7 @@ public class VolumeApiServiceImpl extends ManagerBase 
implements VolumeApiServic
             }
         }
 
+        removeVolume(volume.getId());
         return volume;
     }
 
@@ -1621,6 +1629,9 @@ public class VolumeApiServiceImpl extends ManagerBase 
implements VolumeApiServic
 
         if (destPrimaryStorage != null && (volumeToAttach.getState() == 
Volume.State.Allocated || volumeOnSecondary)) {
             try {
+                if (volumeOnSecondary && destPrimaryStorage.getPoolType() == 
Storage.StoragePoolType.PowerFlex) {
+                    throw new InvalidParameterValueException("Cannot attach 
uploaded volume, this operation is unsupported on storage pool type " + 
destPrimaryStorage.getPoolType());
+                }
                 newVolumeOnPrimaryStorage = 
_volumeMgr.createVolumeOnPrimaryStorage(vm, volumeToAttach, rootDiskHyperType, 
destPrimaryStorage);
             } catch (NoTransitionException e) {
                 s_logger.debug("Failed to create volume on primary storage", 
e);

Reply via email to