diff --git a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/CinderApi.java b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/CinderApi.java index 43a2ed3e1f..7cd0f5548a 100644 --- a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/CinderApi.java +++ b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/CinderApi.java @@ -24,6 +24,8 @@ import org.jclouds.location.functions.RegionToEndpoint; import org.jclouds.openstack.cinder.v1.domain.Snapshot; import org.jclouds.openstack.cinder.v1.domain.Volume; import org.jclouds.openstack.cinder.v1.domain.VolumeType; +import org.jclouds.javax.annotation.Nullable; +import org.jclouds.openstack.cinder.v1.extensions.AvailabilityZoneApi; import org.jclouds.openstack.cinder.v1.features.QuotaApi; import org.jclouds.openstack.cinder.v1.features.SnapshotApi; import org.jclouds.openstack.cinder.v1.features.VolumeApi; @@ -77,6 +79,13 @@ public interface CinderApi extends Closeable { @Delegate QuotaApi getQuotaApi(@EndpointParam(parser = RegionToEndpoint.class) String region); + /** + * Provides access to Availability Zone features + */ + @Delegate + AvailabilityZoneApi getAvailabilityZoneApi( + @EndpointParam(parser = RegionToEndpoint.class) @Nullable String region); + /** * @return the Zone codes configured * @deprecated Please use {@link #getConfiguredRegions()} as this method will be removed in jclouds 3.0. @@ -125,5 +134,4 @@ public interface CinderApi extends Closeable { @Delegate SnapshotApi getSnapshotApiForZone( @EndpointParam(parser = RegionToEndpoint.class) String zone); - } diff --git a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/domain/AvailabilityZone.java b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/domain/AvailabilityZone.java new file mode 100644 index 0000000000..d7d1bfbe59 --- /dev/null +++ b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/domain/AvailabilityZone.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.domain; + +import com.google.common.base.Objects; +import java.beans.ConstructorProperties; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * availability zone for cinder + */ +public class AvailabilityZone { + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromAvailabilityZone(this); + } + + public static class Builder { + + protected boolean available; + protected String name; + + /** + * @see AvailabilityZone#getName() + */ + public Builder name(String name) { + this.name = name; + return this; + } + + /** + * @see AvailabilityZone#getZoneState() + */ + public Builder available(boolean available) { + this.available = available; + return this; + } + + + public AvailabilityZone build() { + return new AvailabilityZone(name, new ZoneState(available)); + } + + public Builder fromAvailabilityZone(AvailabilityZone in) { + return this + .name(in.getName()) + .available(in.getZoneState().available()); + } + } + + private final String name; + private final ZoneState state; + + @ConstructorProperties({"zoneName", "zoneState"}) + protected AvailabilityZone(String name, ZoneState zoneState) { + this.name = checkNotNull(name); + this.state = checkNotNull(zoneState); + } + + public String getName() { + return this.name; + } + + public ZoneState getZoneState() { + return this.state; + } + + @Override + public int hashCode() { + return Objects.hashCode(name, state); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + AvailabilityZone that = AvailabilityZone.class.cast(obj); + return Objects.equal(this.name, that.name) && Objects.equal(this.state, that.state); + } + + protected Objects.ToStringHelper string() { + return Objects.toStringHelper(this) + .add("name", name) + .add("state", state); + } + + @Override + public String toString() { + return string().toString(); + } + +} diff --git a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/domain/ZoneState.java b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/domain/ZoneState.java new file mode 100644 index 0000000000..0db5797199 --- /dev/null +++ b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/domain/ZoneState.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.domain; + +import com.google.common.base.Objects; + +import java.beans.ConstructorProperties; + +/** + * zone state for availability zones + */ +public class ZoneState { + + public static Builder builder() { + return new Builder(); + } + + public Builder toBuilder() { + return new Builder().fromZoneState(this); + } + + public static class Builder { + + protected boolean available; + + /** + * @see ZoneState#available() () + */ + public Builder available(Boolean available) { + this.available = available; + return this; + } + + public ZoneState build() { + return new ZoneState(available); + } + + public Builder fromZoneState(ZoneState in) { + return this + .available(in.available()); + } + } + + private final Boolean available; + + @ConstructorProperties({"available"}) + protected ZoneState(Boolean available) { + this.available = available; + } + + public boolean available() { + return this.available; + } + + @Override + public int hashCode() { + return Objects.hashCode(available); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + ZoneState that = ZoneState.class.cast(obj); + return Objects.equal(this.available, that.available); + } + + protected Objects.ToStringHelper string() { + return Objects.toStringHelper(this) + .add("available", available); + } + + @Override + public String toString() { + return string().toString(); + } + +} diff --git a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/extensions/AvailabilityZoneApi.java b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/extensions/AvailabilityZoneApi.java new file mode 100644 index 0000000000..4b2abdb08b --- /dev/null +++ b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/extensions/AvailabilityZoneApi.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.extensions; + +import com.google.common.annotations.Beta; +import com.google.common.collect.FluentIterable; +import org.jclouds.Fallbacks; +import org.jclouds.openstack.cinder.v1.domain.AvailabilityZone; +import org.jclouds.openstack.keystone.v2_0.filters.AuthenticateRequest; +import org.jclouds.openstack.v2_0.ServiceType; +import org.jclouds.openstack.v2_0.services.Extension; +import org.jclouds.rest.annotations.Fallback; +import org.jclouds.rest.annotations.RequestFilters; +import org.jclouds.rest.annotations.SelectJson; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.MediaType; + +/** + * Provides access to the OpenStack Block Storage (Cinder) Availability Zone Extension API. + */ +@Beta +@Extension(of = ServiceType.BLOCK_STORAGE, namespace = ExtensionNamespaces.ADMIN_ACTIONS) +@RequestFilters(AuthenticateRequest.class) +@Consumes(MediaType.APPLICATION_JSON) +@Path("/os-availability-zone") +public interface AvailabilityZoneApi { + + /** + * Lists all availability zones + * + * @return all availability zones + */ + @GET + @SelectJson("availabilityZoneInfo") + @Fallback(Fallbacks.EmptyFluentIterableOnNotFoundOr404.class) + FluentIterable list(); + +} diff --git a/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/extensions/ExtensionNamespaces.java b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/extensions/ExtensionNamespaces.java new file mode 100644 index 0000000000..4297f6908c --- /dev/null +++ b/apis/openstack-cinder/src/main/java/org/jclouds/openstack/cinder/v1/extensions/ExtensionNamespaces.java @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.extensions; + +/** + * Extension namespaces + */ +public final class ExtensionNamespaces { + + /** + * Admin Action extension + */ + public static final String ADMIN_ACTIONS = "http://docs.openstack.org/ext/admin-actions/api/v1.1"; + + private ExtensionNamespaces() { + throw new AssertionError("intentionally unimplemented"); + } +} diff --git a/apis/openstack-cinder/src/test/java/org/jclouds/openstack/cinder/v1/features/AvailabilityZoneApiExpectTest.java b/apis/openstack-cinder/src/test/java/org/jclouds/openstack/cinder/v1/features/AvailabilityZoneApiExpectTest.java new file mode 100644 index 0000000000..b1c07faec1 --- /dev/null +++ b/apis/openstack-cinder/src/test/java/org/jclouds/openstack/cinder/v1/features/AvailabilityZoneApiExpectTest.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.features; + +import com.google.common.collect.Iterables; +import org.jclouds.http.HttpResponse; +import org.jclouds.openstack.cinder.v1.domain.AvailabilityZone; +import org.jclouds.openstack.cinder.v1.extensions.AvailabilityZoneApi; +import org.jclouds.openstack.cinder.v1.internal.BaseCinderApiExpectTest; +import org.testng.annotations.Test; + +import java.net.URI; +import java.util.Set; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; + +@Test(groups = "unit", testName = "AvailabilityZoneApiExpectTest") +public class AvailabilityZoneApiExpectTest extends BaseCinderApiExpectTest { + + public void testListAvailabilityZones() throws Exception { + URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/os-availability-zone"); + AvailabilityZoneApi api = requestsSendResponses( + keystoneAuthWithUsernameAndPasswordAndTenantName, + responseWithKeystoneAccess, + authenticatedGET().endpoint(endpoint).build(), + HttpResponse.builder().statusCode(200).payload(payloadFromResource("/availability_zones_list.json")).build() + ).getAvailabilityZoneApi("RegionOne"); + + AvailabilityZone availabilityZoneActual = Iterables.getFirst(api.list(), null); + AvailabilityZone availabilityZoneExpected = getTestAvailabilityZone(); + + assertNotNull(availabilityZoneActual); + assertEquals(availabilityZoneActual, availabilityZoneExpected); + } + + public void testListAvailabilityZonesFail() throws Exception { + URI endpoint = URI.create("http://172.16.0.1:8776/v1/50cdb4c60374463198695d9f798fa34d/os-availability-zone"); + AvailabilityZoneApi api = requestsSendResponses( + keystoneAuthWithUsernameAndPasswordAndTenantName, + responseWithKeystoneAccess, + authenticatedGET().endpoint(endpoint).build(), + HttpResponse.builder().statusCode(404).build() + ).getAvailabilityZoneApi("RegionOne"); + + Set availabilityZones = api.list().toSet(); + assertTrue(availabilityZones.isEmpty()); + } + + protected AvailabilityZone getTestAvailabilityZone() { + return AvailabilityZone.builder() + .name("nova") + .available(true) + .build(); + } +} diff --git a/apis/openstack-cinder/src/test/java/org/jclouds/openstack/cinder/v1/features/AvailabilityZoneApiLiveTest.java b/apis/openstack-cinder/src/test/java/org/jclouds/openstack/cinder/v1/features/AvailabilityZoneApiLiveTest.java new file mode 100644 index 0000000000..6c3a147e90 --- /dev/null +++ b/apis/openstack-cinder/src/test/java/org/jclouds/openstack/cinder/v1/features/AvailabilityZoneApiLiveTest.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF 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.features; + +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; +import org.jclouds.openstack.cinder.v1.domain.AvailabilityZone; +import org.jclouds.openstack.cinder.v1.extensions.AvailabilityZoneApi; +import org.jclouds.openstack.cinder.v1.internal.BaseCinderApiLiveTest; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import static org.testng.Assert.assertTrue; + +@Test(groups = "live", testName = "AvailabilityZoneApiLiveTest", singleThreaded = true) +public class AvailabilityZoneApiLiveTest extends BaseCinderApiLiveTest { + + private AvailabilityZoneApi availabilityZoneApi; + + public AvailabilityZoneApiLiveTest() { + super(); + provider = "openstack-cinder"; + } + + @BeforeClass(groups = {"integration", "live"}) + public void setupContext() { + super.setup(); + String zone = Iterables.getFirst(api.getConfiguredZones(), "regionOne"); + availabilityZoneApi = api.getAvailabilityZoneApi(zone); + } + + public void testListAvailabilityZones() { + ImmutableList cinderZones = availabilityZoneApi.list().toList(); + + assertTrue(!cinderZones.isEmpty()); + for (AvailabilityZone zone : cinderZones) { + assertTrue(!Strings.isNullOrEmpty(zone.getName())); + assertTrue(zone.getZoneState().available()); + } + + } +} diff --git a/apis/openstack-cinder/src/test/resources/availability_zones_list.json b/apis/openstack-cinder/src/test/resources/availability_zones_list.json new file mode 100644 index 0000000000..ba6a18956f --- /dev/null +++ b/apis/openstack-cinder/src/test/resources/availability_zones_list.json @@ -0,0 +1,8 @@ +{ + "availabilityZoneInfo": [{ + "zoneState": { + "available": true + }, + "zoneName": "nova" + }] +}