mirror of https://github.com/apache/jclouds.git
Merge pull request #986 from rackspace/vol-snap-status-predicate
Added Predicates for handling Volume and Snapshot Status.
This commit is contained in:
commit
560666d412
|
@ -83,9 +83,11 @@ public interface VolumeAttachmentApi {
|
|||
/**
|
||||
* Detach a Volume from a server.
|
||||
*
|
||||
* @param serverId The ID of the Server
|
||||
* Note: Make sure you've unmounted the volume first. Failure to do so could result in failure or data loss.
|
||||
*
|
||||
* @param volumeId The ID of the Volume
|
||||
* @param serverId The ID of the Server
|
||||
* @return true if successful
|
||||
*/
|
||||
boolean detachVolumeFromServer(String serverId, String volumeId);
|
||||
boolean detachVolumeFromServer(String volumeId, String serverId);
|
||||
}
|
|
@ -206,6 +206,10 @@ public class Volume {
|
|||
}
|
||||
}
|
||||
|
||||
public static Volume forId(String volumeId) {
|
||||
return builder().id(volumeId).build();
|
||||
}
|
||||
|
||||
private final String id;
|
||||
private final Volume.Status status;
|
||||
private final int size;
|
||||
|
|
|
@ -40,7 +40,7 @@ public interface SnapshotApi {
|
|||
Snapshot get(String snapshotId);
|
||||
|
||||
/**
|
||||
* Creates a new Snapshot
|
||||
* Creates a new Snapshot. The Volume status must be Available.
|
||||
*
|
||||
* @param volumeId The Volume Id from which to create the Snapshot
|
||||
* @param options See CreateSnapshotOptions
|
||||
|
|
|
@ -52,7 +52,7 @@ public interface VolumeApi {
|
|||
Volume create(int sizeGB, CreateVolumeOptions... options);
|
||||
|
||||
/**
|
||||
* Delete a Volume.
|
||||
* Delete a Volume. The Volume status must be Available or Error.
|
||||
*
|
||||
* @param volumeId Id of the Volume
|
||||
* @return true if successful, false otherwise
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.openstack.cinder.v1.predicates;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.openstack.cinder.v1.domain.Snapshot;
|
||||
import org.jclouds.openstack.cinder.v1.domain.Volume;
|
||||
import org.jclouds.openstack.cinder.v1.domain.Volume.Status;
|
||||
import org.jclouds.openstack.cinder.v1.features.SnapshotApi;
|
||||
import org.jclouds.predicates.RetryablePredicate;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
/**
|
||||
* Tests to see if snapshot has reached status. This class is most useful when paired with a RetryablePredicate as
|
||||
* in the code below. This class can be used to block execution until the Snapshot status has reached a desired state.
|
||||
* This is useful when your Snapshot needs to be 100% ready before you can continue with execution.
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* Snapshot snapshot = snapshotApi.create(volumeId);
|
||||
* RetryablePredicate<String> awaitAvailable = new RetryablePredicate<String>(
|
||||
* SnapshotPredicates.available(snapshotApi), 600, 10, 10, TimeUnit.SECONDS);
|
||||
*
|
||||
* if (!awaitAvailable.apply(snapshot.getId())) {
|
||||
* throw new TimeoutException("Timeout on snapshot: " + snapshot);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* You can also use the static convenience methods as so.
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* Snapshot snapshot = snapshotApi.create(volumeId);
|
||||
*
|
||||
* if (!SnapshotPredicates.awaitAvailable(snapshotApi).apply(snapshot.getId())) {
|
||||
* throw new TimeoutException("Timeout on snapshot: " + snapshot);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
public class SnapshotPredicates {
|
||||
/**
|
||||
* Wait until a Snapshot is Available.
|
||||
*
|
||||
* @param snapshotApi The SnapshotApi in the zone where your Snapshot resides.
|
||||
* @return RetryablePredicate That will check the status every 5 seconds for a maxiumum of 20 minutes.
|
||||
*/
|
||||
public static RetryablePredicate<Snapshot> awaitAvailable(SnapshotApi snapshotApi) {
|
||||
StatusUpdatedPredicate statusPredicate = new StatusUpdatedPredicate(snapshotApi, Volume.Status.AVAILABLE);
|
||||
|
||||
return new RetryablePredicate<Snapshot>(statusPredicate, 1200, 5, 5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public static RetryablePredicate<Snapshot> awaitStatus(
|
||||
SnapshotApi snapshotApi, Volume.Status status, long maxWaitInSec, long periodInSec) {
|
||||
StatusUpdatedPredicate statusPredicate = new StatusUpdatedPredicate(snapshotApi, status);
|
||||
|
||||
return new RetryablePredicate<Snapshot>(statusPredicate, maxWaitInSec, periodInSec, periodInSec, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private static class StatusUpdatedPredicate implements Predicate<Snapshot> {
|
||||
private SnapshotApi snapshotApi;
|
||||
private Status status;
|
||||
|
||||
public StatusUpdatedPredicate(SnapshotApi snapshotApi, Volume.Status status) {
|
||||
this.snapshotApi = checkNotNull(snapshotApi, "snapshotApi must be defined");
|
||||
this.status = checkNotNull(status, "status must be defined");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Return true when the snapshot reaches status, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean apply(Snapshot snapshot) {
|
||||
checkNotNull(snapshot, "snapshotId must be defined");
|
||||
|
||||
if (status.equals(snapshot.getStatus())) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
Snapshot snapshotUpdated = snapshotApi.get(snapshot.getId());
|
||||
checkNotNull(snapshotUpdated, "Snapshot %s not found.", snapshot.getId());
|
||||
|
||||
return status.equals(snapshotUpdated.getStatus());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.openstack.cinder.v1.predicates;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.jclouds.openstack.cinder.v1.domain.Volume;
|
||||
import org.jclouds.openstack.cinder.v1.domain.Volume.Status;
|
||||
import org.jclouds.openstack.cinder.v1.features.VolumeApi;
|
||||
import org.jclouds.predicates.RetryablePredicate;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
|
||||
/**
|
||||
* Tests to see if volume has reached status. This class is most useful when paired with a RetryablePredicate as
|
||||
* in the code below. This class can be used to block execution until the Volume status has reached a desired state.
|
||||
* This is useful when your Volume needs to be 100% ready before you can continue with execution.
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* Volume volume = volumeApi.create(100);
|
||||
*
|
||||
* RetryablePredicate<String> awaitAvailable = new RetryablePredicate<String>(
|
||||
* VolumePredicates.available(volumeApi), 600, 10, 10, TimeUnit.SECONDS);
|
||||
*
|
||||
* if (!awaitAvailable.apply(volume.getId())) {
|
||||
* throw new TimeoutException("Timeout on volume: " + volume);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* You can also use the static convenience methods as so.
|
||||
*
|
||||
* <pre>
|
||||
* {@code
|
||||
* Volume volume = volumeApi.create(100);
|
||||
*
|
||||
* if (!VolumePredicates.awaitAvailable(volumeApi).apply(volume.getId())) {
|
||||
* throw new TimeoutException("Timeout on volume: " + volume);
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author Everett Toews
|
||||
*/
|
||||
public class VolumePredicates {
|
||||
/**
|
||||
* Wait until a Volume is Available.
|
||||
*
|
||||
* @param volumeApi The VolumeApi in the zone where your Volume resides.
|
||||
* @return RetryablePredicate That will check the status every 5 seconds for a maxiumum of 10 minutes.
|
||||
*/
|
||||
public static RetryablePredicate<Volume> awaitAvailable(VolumeApi volumeApi) {
|
||||
StatusUpdatedPredicate statusPredicate = new StatusUpdatedPredicate(volumeApi, Volume.Status.AVAILABLE);
|
||||
|
||||
return new RetryablePredicate<Volume>(statusPredicate, 600, 5, 5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until a Volume is In Use.
|
||||
*
|
||||
* @param volumeApi The VolumeApi in the zone where your Volume resides.
|
||||
* @return RetryablePredicate That will check the status every 5 seconds for a maxiumum of 10 minutes.
|
||||
*/
|
||||
public static RetryablePredicate<Volume> awaitInUse(VolumeApi volumeApi) {
|
||||
StatusUpdatedPredicate statusPredicate = new StatusUpdatedPredicate(volumeApi, Volume.Status.IN_USE);
|
||||
|
||||
return new RetryablePredicate<Volume>(statusPredicate, 600, 5, 5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
public static RetryablePredicate<Volume> awaitStatus(
|
||||
VolumeApi volumeApi, Volume.Status status, long maxWaitInSec, long periodInSec) {
|
||||
StatusUpdatedPredicate statusPredicate = new StatusUpdatedPredicate(volumeApi, status);
|
||||
|
||||
return new RetryablePredicate<Volume>(statusPredicate, maxWaitInSec, periodInSec, periodInSec, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private static class StatusUpdatedPredicate implements Predicate<Volume> {
|
||||
private VolumeApi volumeApi;
|
||||
private Status status;
|
||||
|
||||
public StatusUpdatedPredicate(VolumeApi volumeApi, Volume.Status status) {
|
||||
this.volumeApi = checkNotNull(volumeApi, "volumeApi must be defined");
|
||||
this.status = checkNotNull(status, "status must be defined");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean Return true when the volume reaches status, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean apply(Volume volume) {
|
||||
checkNotNull(volume, "volume must be defined");
|
||||
|
||||
if (status.equals(volume.getStatus())) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
Volume volumeUpdated = volumeApi.get(volume.getId());
|
||||
checkNotNull(volumeUpdated, "Volume %s not found.", volume.getId());
|
||||
|
||||
return status.equals(volumeUpdated.getStatus());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,6 +29,8 @@ import org.jclouds.openstack.cinder.v1.domain.Volume;
|
|||
import org.jclouds.openstack.cinder.v1.internal.BaseCinderApiLiveTest;
|
||||
import org.jclouds.openstack.cinder.v1.options.CreateSnapshotOptions;
|
||||
import org.jclouds.openstack.cinder.v1.options.CreateVolumeOptions;
|
||||
import org.jclouds.openstack.cinder.v1.predicates.SnapshotPredicates;
|
||||
import org.jclouds.openstack.cinder.v1.predicates.VolumePredicates;
|
||||
import org.jclouds.predicates.RetryablePredicate;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
|
@ -97,12 +99,7 @@ public class VolumeAndSnapshotApiLiveTest extends BaseCinderApiLiveTest {
|
|||
.availabilityZone(zone);
|
||||
testVolume = volumeApi.create(100, options);
|
||||
|
||||
assertTrue(new RetryablePredicate<VolumeApi>(new Predicate<VolumeApi>() {
|
||||
@Override
|
||||
public boolean apply(VolumeApi volumeApi) {
|
||||
return volumeApi.get(testVolume.getId()).getStatus() == Volume.Status.AVAILABLE;
|
||||
}
|
||||
}, 600 * 1000L).apply(volumeApi));
|
||||
assertTrue(VolumePredicates.awaitAvailable(volumeApi).apply(testVolume));
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testCreateVolume")
|
||||
|
@ -152,17 +149,11 @@ public class VolumeAndSnapshotApiLiveTest extends BaseCinderApiLiveTest {
|
|||
"jclouds live test snapshot").force());
|
||||
assertNotNull(testSnapshot);
|
||||
assertNotNull(testSnapshot.getId());
|
||||
final String snapshotId = testSnapshot.getId();
|
||||
assertNotNull(testSnapshot.getStatus());
|
||||
assertTrue(testSnapshot.getSize() > -1);
|
||||
assertNotNull(testSnapshot.getCreated());
|
||||
|
||||
assertTrue(new RetryablePredicate<VolumeApi>(new Predicate<VolumeApi>() {
|
||||
@Override
|
||||
public boolean apply(VolumeApi volumeApi) {
|
||||
return snapshotApi.get(snapshotId).getStatus() == Volume.Status.AVAILABLE;
|
||||
}
|
||||
}, 1200 * 1000L).apply(volumeApi));
|
||||
assertTrue(SnapshotPredicates.awaitAvailable(snapshotApi).apply(testSnapshot));
|
||||
}
|
||||
|
||||
@Test(dependsOnMethods = "testCreateSnapshot")
|
||||
|
|
Loading…
Reference in New Issue