Repository: stratos
Updated Branches:
  refs/heads/master ca95c6d3a -> 7de613562


volume attaching not in order, wait with timeout


Project: http://git-wip-us.apache.org/repos/asf/stratos/repo
Commit: http://git-wip-us.apache.org/repos/asf/stratos/commit/43b19c14
Tree: http://git-wip-us.apache.org/repos/asf/stratos/tree/43b19c14
Diff: http://git-wip-us.apache.org/repos/asf/stratos/diff/43b19c14

Branch: refs/heads/master
Commit: 43b19c1484d4a9df9ba7fcf592a00ba796743758
Parents: ca95c6d
Author: Udara Liyanage <[email protected]>
Authored: Mon May 26 12:33:34 2014 +0530
Committer: Udara Liyanage <[email protected]>
Committed: Wed Jun 4 23:26:27 2014 +0530

----------------------------------------------------------------------
 .../controller/iaases/OpenstackNovaIaas.java    | 187 ++++++++++++-------
 1 file changed, 121 insertions(+), 66 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/stratos/blob/43b19c14/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/iaases/OpenstackNovaIaas.java
----------------------------------------------------------------------
diff --git 
a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/iaases/OpenstackNovaIaas.java
 
b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/iaases/OpenstackNovaIaas.java
index c327002..b4f9c92 100644
--- 
a/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/iaases/OpenstackNovaIaas.java
+++ 
b/components/org.apache.stratos.cloud.controller/src/main/java/org/apache/stratos/cloud/controller/iaases/OpenstackNovaIaas.java
@@ -71,6 +71,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.Set;
+import java.util.concurrent.TimeoutException;
 
 @SuppressWarnings("deprecation")
 public class OpenstackNovaIaas extends Iaas {
@@ -344,7 +345,7 @@ public class OpenstackNovaIaas extends Iaas {
                        }
                        if (ip.equals(fip.getIp())) {
                                if(log.isDebugEnabled()) {
-                                       
log.debug("OpenstackNovaIaas:associatePredefinedAddress:floating ip in use:" + 
fip + " /ip:" + ip);
+                                       
log.debug(String.format("OpenstackNovaIaas:associatePredefinedAddress:floating 
ip in use:%s /ip:%s", fip, ip));
                                }
                                isAvailable = true;
                                break;
@@ -495,8 +496,7 @@ public class OpenstackNovaIaas extends Iaas {
        IaasProvider iaasInfo = getIaasProvider();
        
         if (host == null || zone == null || iaasInfo == null) {
-            String msg = "Host or Zone or IaaSProvider is null: host: " + host 
+ " - zone: " +
-                    zone + " - IaaSProvider: " + iaasInfo;
+            String msg = String.format("Host or Zone or IaaSProvider is null: 
host: %s - zone: %s - IaaSProvider: %s", host, zone, iaasInfo);
             log.error(msg);
             throw new InvalidHostException(msg);
         }
@@ -514,7 +514,7 @@ public class OpenstackNovaIaas extends Iaas {
             }
         }
         
-        String msg = "Invalid host: " + host +" in the zone: "+zone+ " and of 
the iaas: "+iaasInfo.getType();
+        String msg = String.format("Invalid host: %s in the zone: %s and of 
the iaas: %s", host, zone, iaasInfo.getType());
         log.error(msg);
         throw new InvalidHostException(msg);
     }
@@ -531,97 +531,153 @@ public class OpenstackNovaIaas extends Iaas {
                String zone = ComputeServiceBuilderUtil.extractZone(iaasInfo);
                
         if (region == null || iaasInfo == null) {
-               log.fatal("Cannot create a new volume in the [region] : "+region
-                                       +" of Iaas : "+iaasInfo);
+               log.fatal(String.format("Cannot create a new volume in the 
[region] : %s of Iaas : %s", region, iaasInfo));
             return null;
         }
         ComputeServiceContext context = 
iaasInfo.getComputeService().getContext();
         
         RestContext<NovaApi, NovaAsyncApi> nova = context.unwrap();
-        VolumeApi api = nova.getApi().getVolumeExtensionForZone(region).get();
+        VolumeApi volumeApi = 
nova.getApi().getVolumeExtensionForZone(region).get();
         Volume volume;
         if(StringUtils.isEmpty(snapshotId)){
                if(log.isDebugEnabled()){
                        log.info("Creating a volume in the zone " + zone);
                }
-               volume = api.create(sizeGB, 
CreateVolumeOptions.Builder.availabilityZone(zone));
+               volume = volumeApi.create(sizeGB, 
CreateVolumeOptions.Builder.availabilityZone(zone));
         }else{
                if(log.isDebugEnabled()){
                        log.info("Creating a volume in the zone " + zone + " 
from the shanpshot " + snapshotId);
                }
-               volume = api.create(sizeGB, 
CreateVolumeOptions.Builder.availabilityZone(zone).snapshotId(snapshotId));
+               volume = volumeApi.create(sizeGB, 
CreateVolumeOptions.Builder.availabilityZone(zone).snapshotId(snapshotId));
         }
+
         if (volume == null) {
-                       log.fatal("Volume creation was unsuccessful. [region] : 
" + region+" [zone] : " + zone
-                                       + " of Iaas : " + iaasInfo);
-                       return null;
-               }        
+            log.fatal(String.format("Volume creation was unsuccessful. 
[region] : %s [zone] : %s of Iaas : %s", region, zone, iaasInfo));
+            return null;
+        }
+
+        String volumeId = volume.getId();
+        /*
+        Volume.Status volumeStatus = this.getVolumeStatus(volumeApi, volumeId);
 
-               log.info("Successfully created a new volume [id]: 
"+volume.getId()
-                               +" in [region] : "+region+" [zone] : "+zone+" 
of Iaas : "+iaasInfo + " [Volume ID]" + volume.getId());
-               return volume.getId();
+        if(!(volumeStatus == Volume.Status.AVAILABLE || volumeStatus == 
Volume.Status.CREATING)){
+            log.error(String.format("Error while creating [volume id] %s. 
Volume status is %s", volumeId, volumeStatus));
+            return volumeId;
+        }
+        try {
+            if(!waitForStatus(volumeApi, volumeId, Volume.Status.AVAILABLE)){
+                log.error("Volume did not become AVAILABLE. Current status is 
" + volume.getStatus());
+            }
+        } catch (TimeoutException e) {
+            log.error("[Volume ID] " + volumeId + "did not become AVAILABLE 
within expected timeout");
+            return volumeId;
+        }
+        */
+               log.info(String.format("Successfully created a new volume [id]: 
%s in [region] : %s [zone] : %s of Iaas : %s [Volume ID]%s", volume.getId(), 
region, zone, iaasInfo, volume.getId()));
+               return volumeId;
        }
 
-       @Override
+    private boolean waitForStatus(String volumeId, Volume.Status 
expectedStatus, int timeoutInMins) throws TimeoutException {
+        long timeout = 1000 * 60 * timeoutInMins;//5mins
+        long t0 = System.currentTimeMillis() + timeout;
+
+        IaasProvider iaasInfo = getIaasProvider();
+        String region = ComputeServiceBuilderUtil.extractRegion(iaasInfo);
+        ComputeServiceContext context = 
iaasInfo.getComputeService().getContext();;
+        RestContext<NovaApi, NovaAsyncApi> nova = context.unwrap();
+        VolumeApi volumeApi = 
nova.getApi().getVolumeExtensionForZone(region).get();
+        VolumeAttachmentApi volumeAttachmentApi = 
nova.getApi().getVolumeAttachmentExtensionForZone(region).get();
+        Volume.Status volumeStatus = this.getVolumeStatus(volumeApi, volumeId);
+
+        while(volumeStatus != expectedStatus){
+            try {
+                if(log.isDebugEnabled()){
+                    log.debug(String.format("Volume %s is still NOT in %s. 
Current State=%s", volumeId, expectedStatus, volumeStatus));
+                }
+                if(volumeStatus == Volume.Status.ERROR){
+                    log.error("Volume " + volumeId + " is in state ERROR");
+                    return false;
+                }
+                Thread.sleep(1000);
+                volumeStatus = this.getVolumeStatus(volumeApi, volumeId);
+                if (System.currentTimeMillis()> t0) {
+                    throw new TimeoutException();
+                }
+            } catch (InterruptedException e) {
+                // Ignoring the exception
+            }
+        }
+        if(log.isDebugEnabled()){
+            log.debug(String.format("Volume %s status became %s", volumeId, 
expectedStatus));
+        }
+
+        return true;
+    }
+
+    @Override
        public String attachVolume(String instanceId, String volumeId, String 
deviceName) {
-               IaasProvider iaasInfo = getIaasProvider();
+        IaasProvider iaasInfo = getIaasProvider();
 
-               ComputeServiceContext context = iaasInfo.getComputeService()
-                               .getContext();
-               
-               String region = 
ComputeServiceBuilderUtil.extractRegion(iaasInfo);
-               String device = deviceName == null ? "/dev/vdc" : deviceName;
-               
-               if(region == null) {
-                       log.fatal("Cannot attach the volume [id]: "+volumeId+" 
in the [region] : "+region
-                                       +" of Iaas : "+iaasInfo);
-                       return null;
-               }
+        if (StringUtils.isEmpty(volumeId)) {
+            log.error("Volume provided to attach can not be null");
+        }
 
-               RestContext<NovaApi, NovaAsyncApi> nova = context.unwrap();
+        if (StringUtils.isEmpty(instanceId)) {
+            log.error("Instance provided to attach can not be null");
+        }
+
+        ComputeServiceContext context = iaasInfo.getComputeService()
+                .getContext();
+        String region = ComputeServiceBuilderUtil.extractRegion(iaasInfo);
+        String device = deviceName == null ? "/dev/vdc" : deviceName;
 
+        if (region == null) {
+            log.fatal(String.format("Cannot attach the volume [id]: %s in the 
[region] : %s of Iaas : %s", volumeId, region, iaasInfo));
+            return null;
+        }
+
+        RestContext<NovaApi, NovaAsyncApi> nova = context.unwrap();
         VolumeApi volumeApi = 
nova.getApi().getVolumeExtensionForZone(region).get();
+        VolumeAttachmentApi volumeAttachmentApi = 
nova.getApi().getVolumeAttachmentExtensionForZone(region).get();
 
         Volume.Status volumeStatus = this.getVolumeStatus(volumeApi, volumeId);
 
-        if(log.isDebugEnabled()){
+        if (log.isDebugEnabled()) {
             log.debug("Volume " + volumeId + " is in state " + volumeStatus);
         }
 
-        if(!(volumeStatus == Volume.Status.AVAILABLE || volumeStatus == 
Volume.Status.CREATING)){
+        if (!(volumeStatus == Volume.Status.AVAILABLE || volumeStatus == 
Volume.Status.CREATING)) {
             log.error(String.format("Volume %s can not be attached. Volume 
status is %s", volumeId, volumeStatus));
             return null;
         }
 
-        /* Coming here means @volumeStatus is VAILABLE  or CREATING. waiting 
till it becomes AVAILABLE. */
-        while(volumeStatus != Volume.Status.AVAILABLE){
+        boolean volumeBecameAvailable = false, volumeBecameAttached = false;
+        try {
+            volumeBecameAvailable = waitForStatus(volumeId, 
Volume.Status.AVAILABLE, 5);
+        } catch (TimeoutException e) {
+            log.error("[Volume ID] " + volumeId + "did not become AVAILABLE 
within expected timeout");
+        }
+
+        VolumeAttachment attachment = null;
+        if (volumeBecameAvailable) {
+            attachment = 
volumeAttachmentApi.attachVolumeToServerAsDevice(volumeId, instanceId, device);
+
             try {
-                // TODO Use a proper mechanism to wait till volume becomes 
available.
-                Thread.sleep(100);
-                volumeStatus = this.getVolumeStatus(volumeApi, volumeId);
-                if(log.isDebugEnabled()){
-                    log.debug("Volume " + volumeId + " is still NOT in 
AVAILABLE. Current State=" + volumeStatus);
-                }
-            } catch (InterruptedException e) {
-                // Ignoring the exception
+                volumeBecameAttached = waitForStatus(volumeId, 
Volume.Status.IN_USE, 2);
+            } catch (TimeoutException e) {
+                log.error("[Volume ID] " + volumeId + "did not become IN_USE 
within expected timeout");
             }
         }
-        if(log.isDebugEnabled()){
-            log.debug("Volume " + volumeId + " became  AVAILABLE");
-        }
-
-        VolumeAttachmentApi volumeAttachmentApi = 
nova.getApi().getVolumeAttachmentExtensionForZone(region).get();
-        VolumeAttachment attachment = 
volumeAttachmentApi.attachVolumeToServerAsDevice(volumeId, instanceId, device);
         if (attachment == null) {
-                       log.fatal("Volume [id]: "+volumeId+" attachment for 
instance [id]: "+instanceId
-                                       +" was unsuccessful. [region] : " + 
region
-                                       + " of Iaas : " + iaasInfo);
+                       log.fatal(String.format("Volume [id]: %s attachment for 
instance [id]: %s was unsuccessful. [region] : %s of Iaas : %s", volumeId, 
instanceId, region, iaasInfo));
                        return null;
                }
-               
-               log.info("Volume [id]: "+volumeId+" attachment for instance 
[id]: "+instanceId
-                               +" was successful [status]: "+"Attaching"+". 
[region] : " + region
-                               + " of Iaas : " + iaasInfo);
+
+        if(! volumeBecameAttached){
+           log.error(String.format("[Volume ID] %s attachment is called, but 
not yet became attached", volumeId));
+        }
+
+               log.info(String.format("Volume [id]: %s attachment for instance 
[id]: %s was successful [status]: Attaching. [region] : %s of Iaas : %s", 
volumeId, instanceId, region, iaasInfo));
                return "Attaching";
        }
 
@@ -635,18 +691,19 @@ public class OpenstackNovaIaas extends Iaas {
                String region = 
ComputeServiceBuilderUtil.extractRegion(iaasInfo);
                
                if(region == null) {
-                       log.fatal("Cannot detach the volume [id]: "+volumeId+" 
from the instance [id]: "+instanceId
-                                       +" of the [region] : "+region
-                                       +" of Iaas : "+iaasInfo);
+                       log.fatal(String.format("Cannot detach the volume [id]: 
%s from the instance [id]: %s of the [region] : %s of Iaas : %s", volumeId, 
instanceId, region, iaasInfo));
                        return;
                }
-               
+        if(log.isDebugEnabled()) {
+            log.debug(String.format("Starting to detach volume %s from the 
instance %s", volumeId, instanceId));
+        }
+
                RestContext<NovaApi, NovaAsyncApi> nova = context.unwrap();
         VolumeAttachmentApi api = 
nova.getApi().getVolumeAttachmentExtensionForZone(region).get();
         if (api.detachVolumeFromServer(volumeId, instanceId)) {
-               log.info("Detachment of Volume [id]: "+volumeId+" from instance 
[id]: "+instanceId
-                               +" was successful. [region] : " + region
-                               + " of Iaas : " + iaasInfo);
+               log.info(String.format("Detachment of Volume [id]: %s from 
instance [id]: %s was successful. [region] : %s of Iaas : %s", volumeId, 
instanceId, region, iaasInfo));
+        }else{
+            log.error(String.format("Detachment of Volume [id]: %s from 
instance [id]: %s was unsuccessful. [volume Status] : %s", volumeId, 
instanceId, region, iaasInfo));
         }
         
        }
@@ -661,16 +718,14 @@ public class OpenstackNovaIaas extends Iaas {
                String region = 
ComputeServiceBuilderUtil.extractRegion(iaasInfo);
                
                if(region == null) {
-                       log.fatal("Cannot delete the volume [id]: "+volumeId+" 
of the [region] : "+region
-                                       +" of Iaas : "+iaasInfo);
+                       log.fatal(String.format("Cannot delete the volume [id]: 
%s of the [region] : %s of Iaas : %s", volumeId, region, iaasInfo));
                        return;
                }
                
                RestContext<NovaApi, NovaAsyncApi> nova = context.unwrap();
                VolumeApi api = 
nova.getApi().getVolumeExtensionForZone(region).get();
         if (api.delete(volumeId)) {
-               log.info("Deletion of Volume [id]: "+volumeId+" was successful. 
[region] : " + region
-                               + " of Iaas : " + iaasInfo);
+               log.info(String.format("Deletion of Volume [id]: %s was 
successful. [region] : %s of Iaas : %s", volumeId, region, iaasInfo));
         }
        }
 

Reply via email to