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)); } }
